﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;



namespace Elixi_AntdUi
{
    public partial class HFReader : Form
    {
        private int serialDevice;                   //串口设备this.comboBoxBaudrate.SelectedIndex = 1;
        private int hHFREADERDLLModule;               //dll句柄

        private int[] usbHandleList = new int[256];
        private int usbDevNum = 0;
        public string deviceTypeStr = "";
        private bool bFormOk = false;

        private int netDeviceNum = 0;
        private string[] netDeviceMacInfo = new string[256];
        private string[] netDeviceIpInfo = new string[256];
        private string[] netDevicePortInfo = new string[256];

        private int directOpTimer = 0;
        private Byte[] opTagUid = new Byte[8 * 256];
        private int opTagUidNum = 0;

        #region 彻底删除线程，避免堵塞

        // 新增：记录当前连接类型（解决关闭时调用正确SDK接口的问题）
        private ConnectionType _currentConnType = ConnectionType.None;

        // 1. 后台任务相关（示例：模拟耗时线程）
        private CancellationTokenSource _cts; // 用于取消后台任务
        private Task _backgroundTask; // 后台任务引用

        // 2. 数据更新事件（原逻辑保留）
        public event Action<string> FormDataUpdated;// 数据更新事件（不变）
        // 数据更新事件（向窗体1传递最终确认数据，可选）
        public event Action<string, string> SensorsConfirmed;
        #endregion
        #region   感应器 全局变量（跟踪状态与历史数据）
        // 1. 自动启动步骤枚举（跟踪初始化进度）
        private enum AutoStartStep
        {
            NotStarted,
            SelfTest,       // 自检
            OpenSerial,     // 打开串口
            ConfigReader,   // 配置阅读器
            ReadConfig,     // 读取配置
            SwitchTab15693, // 切换到ISO15693页面
            SwitchTabOperate,// 切换到操作标签页面
            ExecTagOp,      // 执行标签操作
            Completed,      // 全部完成
            Failed          // 某步骤失败
        }

        // 2. 自动启动相关状态
        private AutoStartStep _currentAutoStep = AutoStartStep.NotStarted;
        private const int MaxRetryCount = 3; // 最大重试次数（可配置）
        private int _loopInterval = 1000;    // 循环扫描间隔（1秒，可配置）

        // 3. 传感器识别历史记录（存储上一次确认的结果，用于重复判断）
        private HashSet<string> _lastConfirmedSensors = new HashSet<string>();
        // 4. 临时存储当前识别的传感器ID（避免UI控件直接频繁读写）
        private List<string> _currentSensors = new List<string>();

        // 5. 自检错误信息（用于提示具体问题）
        private string _selfTestErrorMsg = string.Empty;
        // 单传感器超时计数器（优化逻辑中新增，避免无限等待） // 新增全局变量：单传感器等待超时计数器
        private int _singleSensorWaitCount = 0;
        private const int SingleSensorTimeoutCount = 30; // 超时阈值：30次扫描（30秒，1秒/次）

        // 停止状态标记（控制定时器扫描是否执行）
        private bool _isStopped = false;

        // 停止倒计时定时器（10秒后触发恢复）
        private System.Windows.Forms.Timer _stopTimer = new System.Windows.Forms.Timer();

        // 双传感器首次确认标记（判断是否为第一次识别双传感器）
        private bool _hasFirstTwoSensors = false;



        // 扫描次数计数器（追踪扫描序列，便于调试）
        private int _recognitionCount = 0;

        // 中间变量：保存第一次识别的两个感应器ID
        private string _tempSensor1 = string.Empty;
        // 循环控制标志
        private bool _isLooping = false;

        public delegate void DataUpdatedHandler(string data);
        public event DataUpdatedHandler DataUpdated;

        public string text_SensorID1 = string.Empty;
        public string text_SensorID2 = string.Empty;

        // 替代 _isStopped，控制扫描暂停/恢复（true=允许扫描，false=阻塞）
        private ManualResetEventSlim _scanSignal = new ManualResetEventSlim(true);
        #endregion



        private void Iso15693ImOpInfInit(ref ISO15693_IMOP imOp)
        {
            imOp.antAddr = new Byte[255];
            imOp.opBlockResult = new Byte[256];
            imOp.blockAddr = new Byte[8];
            imOp.block = new Byte[256 * 32 * 4];
            imOp.uid = new Byte[256 * 8];
        }

        public HFReader()
        {
            InitializeComponent();
            this.TopMost = false; // 强制禁用“始终置顶”
            this.comboBoxBaudrate.Text = "38400";
            this.comboBoxBaudrate.SelectedIndex = 0;
            #region 感应器处理 + 状态重置（新增）
            // 1. 重置所有关键状态变量（避免残留旧值）
            serialDevice = -1; // 串口初始状态：未打开
            hHFREADERDLLModule = 0; // DLL初始状态：未加载
            _isStopped = false;
            _isLooping = false;
            _hasFirstTwoSensors = false;
            _lastConfirmedSensors.Clear();
            _currentSensors.Clear();
            _singleSensorWaitCount = 0;
            _recognitionCount = 0;
            text_SensorID1 = string.Empty;
            text_SensorID2 = string.Empty;
            Console.WriteLine($"[窗体初始化] 核心状态变量已重置");

            // 2. 重新初始化取消源和后台任务
            _cts = new CancellationTokenSource();
            StartBackgroundTask();

            // 3. 重新初始化定时器（避免旧定时器影响）
            if (_recognitionTimer != null)
            {
                _recognitionTimer.Dispose();
            }
            _recognitionTimer = new System.Windows.Forms.Timer();
            _recognitionTimer.Interval = 1000;
            _recognitionTimer.Tick += RecognitionTimer_Tick;

            if (_stopTimer != null)
            {
                _stopTimer.Dispose();
            }
            _stopTimer = new System.Windows.Forms.Timer();
            _stopTimer.Tick += StopTimer_Tick;
            #endregion

            // 4. 重新加载DLL（确保每次打开都是新句柄）
            hHFREADERDLLModule = hfReaderDll.LoadLibrary("HFREADER.dll");
            if (hHFREADERDLLModule <= 0)
            {
                MessageBox.Show("装载HFREADER.dll文件失败，请确认HFREADER.dll文件是否存在");
                System.Environment.Exit(0);
            }
            Console.WriteLine($"[窗体初始化] HFREADER.dll加载成功，句柄={hHFREADERDLLModule}");

            // 原有串口下拉框初始化逻辑（保留）
            int i = 0;
            this.comboBoxComPort.Items.Clear();
            UpdateComBox();
            int selectIndex = comboBoxComPort.Items.IndexOf(Settings.Default.com);
            if (selectIndex >= 0)
            {
                comboBoxComPort.SelectedIndex = selectIndex;
            }
            else
            {
                comboBoxComPort.SelectedIndex = -1;
            }

            this.groupBoxIso15693Op.Enabled = false;
            this.Text += "    V" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
        }

        private async void HFReader_Load(object sender, EventArgs e)
        {
            UpdateNetBox();
            // 状态恢复（保留原有逻辑）
            if (Settings.Default.comType == "com")
            {
                this.comboBoxComInterface.SelectedIndex = 0;
                this.comboBoxComPort.Text = Settings.Default.com;
                this.comboBoxBaudrate.Text = Settings.Default.comBr;
            }
            else if (Settings.Default.comType == "usb")
            {
                this.comboBoxComInterface.SelectedIndex = 1;
            }
            else if (Settings.Default.comType == "net")
            {
                this.comboBoxComInterface.SelectedIndex = 2;
            }

            // 新增：确保串口初始状态为“未打开”，避免误判
            if (serialDevice >= 0)
            {
                serialDevice = -1;
                Console.WriteLine($"[Form Load] 重置serialDevice为-1（初始未打开状态）");
            }
            // 禁用“操作组”，避免未开串口时误操作
            this.groupBoxIso15693Op.Enabled = false;
            bFormOk = true;

            Console.WriteLine("程序开始启动，等待5秒确保资源加载完成...");
            await Task.Delay(5000);

           /* //最小化
            this.WindowState = FormWindowState.Minimized;*/
            //自动启动主流程
            await AutoStartSequence();

        }

        private void HFReader_FormClosing(object sender, FormClosingEventArgs e)
        {
            Console.WriteLine($"[窗体关闭] 开始释放资源...");
            // 1. 终止后台线程（修正Task.WaitAll参数格式，解决报错1）
            if (_backgroundTask != null && !_backgroundTask.IsCompleted)
            {
                _cts.Cancel();
                try
                {
                    // 正确用法：第一个参数是Task数组，第二个是超时时间（3秒）
                    bool isTaskCompleted = Task.WaitAll(new[] { _backgroundTask }, 3000);
                    if (isTaskCompleted)
                    {
                        Console.WriteLine($"[窗体关闭] 后台线程已在3秒内正常终止");
                    }
                    else
                    {
                        Console.WriteLine($"[窗体关闭警告] 后台线程3秒内未终止，强制结束（避免死等）");
                    }
                }
                catch (AggregateException ex)
                {
                    Console.WriteLine($"[窗体关闭] 线程终止异常：{ex.InnerException?.Message}");
                }
            }

            // 2. 强制释放串口、DLL等非托管资源（修正SDK接口和类型转换，解决报错2、3）
            ReleaseUnmanagedResources();

            // 3. 解绑事件+重置状态变量
            DataUpdated = null;
            SensorsConfirmed = null;
            serialDevice = -1;
            _currentConnType = ConnectionType.None; // 重置连接类型
            _cts = null;
            _backgroundTask = null;
            Console.WriteLine($"[窗体关闭] 资源释放完成，状态变量已重置");
        }

        /// <summary>
        /// 隐藏窗体
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnHide_Click(object sender, EventArgs e)
        {
            this.Hide(); // 隐藏窗体，实例仍在内存中
        }
        /// <summary>
        /// 保留真正关闭按钮（如需彻底释放Form2）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCloseForm2_Click_1(object sender, EventArgs e)
        {
            this.Close(); // 彻底关闭并释放Form2（此时Form1需重新创建实例）

        }

        /// <summary>
        /// 执行扫描
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button15693DirExec_Click(object sender, EventArgs e)
        {
            // 切换循环状态：如果正在循环则停止，否则开始
            if (_isLooping)
            {
                StopLoop();
                return;
            }

            // 启动循环前的初始化检查（复用原有检查逻辑）
            if (serialDevice < 0)
            {
                MessageBox.Show("请先打开串口");
                return;
            }
            if (this.comboBox15693DirCmdSel.SelectedIndex < 0)
            {
                MessageBox.Show("请选择操作命令");
                return;
            }
            if (this.comboBox15693DirMode.SelectedIndex < 0)
            {
                MessageBox.Show("请选择操作模式");
                return;
            }
            ushort[] addrArray = new ushort[2];
            if (!GetDeviceAddr(addrArray))
            {
                return;
            }

            // 启动循环
            StartLoop(addrArray);


        }


        #region 原代码
        public int GetHexInput(String s, Byte[] buffer)
        {
            int i = 0;
            int num = 0;
            for (i = 0; i < s.Length; i++)
            {
                char c = s[i];
                if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F'))
                {
                    MessageBox.Show("请以16进制格式输入数据，例如：00 01 FF");
                    return 0;
                }
            }
            num = s.Length / 2;
            for (i = 0; i < num; i++)
            {
                buffer[i] = Convert.ToByte(s.Substring(i * 2, 2), 16);
            }

            return num;
        }

        public int GetHexInput(String s, Byte[] buffer, int num)
        {
            int i = 0;
            if (s.Length != 2 * num)
            {
                MessageBox.Show("数据长度错误");
                return -1;
            }
            for (i = 0; i < s.Length; i++)
            {
                char c = s[i];
                if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F'))
                {
                    MessageBox.Show("请以16进制格式输入数据，例如：00 01 FF");
                    return -1;
                }
            }
            for (i = 0; i < num; i++)
            {
                buffer[i] = Convert.ToByte(s.Substring(i * 2, 2), 16);
            }

            return num;
        }

        public bool GetDeviceAddr(ushort[] addArray)
        {
            bool b = false;
            byte[] buffer = new Byte[255];
            addArray[0] = 0x0000;
            if (GetHexInput(textBoxDestAddr.Text, buffer, 2) > 0)
            {
                addArray[1] = (ushort)(buffer[0] * 256 + buffer[1]);
                b = true;
            }

            return b;
        }
        private void UpdateComBox()
        {
            string[] portList = System.IO.Ports.SerialPort.GetPortNames();
            int i = 0;
            for (i = 0; i < comboBoxComPort.Items.Count; ++i)
            {
                int j = 0;
                string name = comboBoxComPort.Items[i].ToString();
                for (j = 0; j < portList.Length; j++)
                {
                    if (portList[j] == name)
                    {
                        break;
                    }
                }
                if (j == portList.Length)
                {
                    comboBoxComPort.Items.Remove(name);
                    comboBoxComPort.SelectedIndex = -1;
                }
            }
            for (i = 0; i < portList.Length; ++i)
            {
                string name = portList[i];
                if (comboBoxComPort.Items.IndexOf(name) < 0)
                {
                    comboBoxComPort.Items.Add(name);
                }
            }
        }
        private void comboBoxComPort_DropDown(object sender, EventArgs e)
        {
            UpdateComBox();
        }
        private void UpdateNetBox()
        {
            int i = 0;
            int settingIndex = -1;
            netDeviceNum = 0;
            ScanAnyIDNetDevices();
            ScanUsrNetDevices();
            for (i = 0; i < netDeviceNum; i++)
            {
                comboBoxComPort.Items.Add(netDeviceIpInfo[i]);
                comboBoxBaudrate.Items.Add(netDevicePortInfo[i]);

                if (Settings.Default.netIp + " " + Settings.Default.netPort == netDeviceIpInfo[i] + " " + netDevicePortInfo[i])
                {
                    settingIndex = i;
                }
            }
            if (netDeviceNum > 0)
            {
                if (settingIndex < 0)
                {
                    settingIndex = 0;
                }
                comboBoxComPort.SelectedIndex = settingIndex;
                comboBoxBaudrate.SelectedIndex = settingIndex;
            }
            else
            {
                if (Settings.Default.netIp.Length > 0)
                {
                    comboBoxComPort.Items.Add(Settings.Default.netIp);
                    comboBoxBaudrate.Items.Add(Settings.Default.netPort);

                    comboBoxComPort.SelectedIndex = 0;
                    comboBoxBaudrate.SelectedIndex = 0;
                }
            }
        }

        private void ScanUsrNetDevices()
        {
            IPAddress[] localIpList = new IPAddress[256];
            int localIpNum = 0;

            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                {
                    localIpList[localIpNum++] = _IPAddress;
                }
            }

            int n = 0;
            UdpClient localUdpClient = null;
            for (n = 0; n < localIpNum; n++)
            {
                try
                {
                    IPEndPoint localUdpPoint = new IPEndPoint(localIpList[n], 53453);
                    localUdpClient = new UdpClient(localUdpPoint);
                    localUdpClient.Client.SendTimeout = 500;
                    localUdpClient.Client.ReceiveTimeout = 500;
                    IPEndPoint deviceUdpPoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 1500);

                    byte[] cmdScan = { 0xFF, 0x01, 0x01, 0x02 };
                    localUdpClient.Send(cmdScan, cmdScan.Length, deviceUdpPoint);
                    while (true)
                    {
                        try
                        {
                            byte[] recvData = localUdpClient.Receive(ref deviceUdpPoint);
                            if (recvData != null)
                            {
                                int i = 0;
                                string macStr = "";

                                macStr += recvData[9].ToString("X").PadLeft(2, '0') + ":";
                                macStr += recvData[10].ToString("X").PadLeft(2, '0') + ":";
                                macStr += recvData[11].ToString("X").PadLeft(2, '0') + ":";
                                macStr += recvData[12].ToString("X").PadLeft(2, '0') + ":";
                                macStr += recvData[13].ToString("X").PadLeft(2, '0') + ":";
                                macStr += recvData[14].ToString("X").PadLeft(2, '0');
                                for (i = 0; i < netDeviceNum; i++)
                                {
                                    if (netDeviceMacInfo[i] == macStr)
                                    {
                                        break;
                                    }
                                }
                                if (i == netDeviceNum)
                                {
                                    string devicePortStr = "", deviceIpStr = "";
                                    if (ReadNetDeviceInfo(localIpList[n], recvData, ref devicePortStr, ref deviceIpStr))
                                    {
                                        netDeviceMacInfo[netDeviceNum] = macStr;
                                        netDeviceIpInfo[netDeviceNum] = deviceIpStr;
                                        netDevicePortInfo[netDeviceNum] = devicePortStr;
                                        netDeviceNum++;
                                    }
                                }

                                Thread.Sleep(10);
                            }
                            else
                            {
                                localUdpClient.Close();
                                break;
                            }
                        }
                        catch (Exception ex)
                        {
                            localUdpClient.Close();
                            break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (localUdpClient != null)
                    {
                        localUdpClient.Close();
                    }
                }
            }
        }
        private void ScanAnyIDNetDevices()
        {
            IPAddress[] localIpList = new IPAddress[256];
            int localIpNum = 0;

            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                {
                    localIpList[localIpNum++] = _IPAddress;
                }
            }

            int n = 0;
            UdpClient localUdpClient = null;
            for (n = 0; n < localIpNum; n++)
            {
                try
                {
                    IPEndPoint localUdpPoint = new IPEndPoint(localIpList[n], 53453);
                    localUdpClient = new UdpClient(localUdpPoint);
                    localUdpClient.Client.SendTimeout = 500;
                    localUdpClient.Client.ReceiveTimeout = 500;
                    IPEndPoint deviceUdpPoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 1092);

                    byte[] cmdScan = new byte[3 + 167];
                    cmdScan[0] = 0x5A;
                    cmdScan[1] = 0x4C;
                    cmdScan[2] = 0x00;
                    localUdpClient.Send(cmdScan, cmdScan.Length, deviceUdpPoint);
                    while (true)
                    {
                        try
                        {
                            byte[] recvData = localUdpClient.Receive(ref deviceUdpPoint);
                            if (recvData != null && recvData.Length == 3 + 167)
                            {
                                if (recvData[0] == 0x5A && recvData[1] == 0x4C && recvData[2] == 0x01)
                                {
                                    int i = 0;
                                    string strMac = "", devicePortStr = "", deviceIpStr = "";
                                    //3-head-0
                                    //4-localip-3 
                                    //4-mask-7 
                                    //4-gateway-11
                                    //4-remoteip-15
                                    //2-localport-19 
                                    //2-destport-21 
                                    //1-workmode-23
                                    //10-rfu-24 
                                    //6-id-34 
                                    //1-baudrate-40
                                    //10-deviceName-41
                                    //1-parity-51
                                    //1-gaptime-52
                                    //2-packetlen-53
                                    //1-f_enden-55
                                    //1-f_enbyte-56
                                    //1-f_starten-57
                                    //1-f_startbyte-58
                                    //1-dhcpen-59
                                    strMac += recvData[34].ToString("X").PadLeft(2, '0') + ":";
                                    strMac += recvData[35].ToString("X").PadLeft(2, '0') + ":";
                                    strMac += recvData[36].ToString("X").PadLeft(2, '0') + ":";
                                    strMac += recvData[37].ToString("X").PadLeft(2, '0') + ":";
                                    strMac += recvData[38].ToString("X").PadLeft(2, '0') + ":";
                                    strMac += recvData[39].ToString("X").PadLeft(2, '0');

                                    {
                                        for (i = 0; i < netDeviceNum; i++)
                                        {
                                            if (netDeviceMacInfo[i] == strMac)
                                            {
                                                break;
                                            }
                                        }
                                        if (i == netDeviceNum)
                                        {
                                            deviceIpStr = recvData[3].ToString() + "." + recvData[4].ToString() + "." + recvData[5].ToString() + "." + recvData[6].ToString();
                                            devicePortStr = (recvData[20] + recvData[19] * 256).ToString();

                                            netDeviceMacInfo[netDeviceNum] = strMac;
                                            netDeviceIpInfo[netDeviceNum] = deviceIpStr;
                                            netDevicePortInfo[netDeviceNum] = devicePortStr;
                                            netDeviceNum++;
                                        }
                                    }
                                }
                                Thread.Sleep(10);
                            }
                            else
                            {
                                localUdpClient.Close();
                                break;
                            }
                        }
                        catch (Exception ex)
                        {
                            localUdpClient.Close();
                            break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (localUdpClient != null)
                    {
                        localUdpClient.Close();
                    }
                }
            }
        }
        private bool ReadNetDeviceInfo(IPAddress masterIp, Byte[] deviceParams, ref string portStr, ref string ipStr)
        {
            byte[] txCmd = { 0xFF, 0x13, 0x03, 0xD8, 0xB0, 0x4C, 0x46, 0x35, 0xCA, 0x61, 0x64, 0x6D, 0x69, 0x6E, 0x00, 0x61, 0x64, 0x6D, 0x69, 0x6E, 0x00, 0x41 };
            byte chk = 0;
            int i = 0;

            for (i = 0; i < 6; i++)
            {
                txCmd[3 + i] = deviceParams[9 + i];
            }
            for (i = 0; i < 20; i++)
            {
                chk += txCmd[1 + i];
            }
            txCmd[21] = chk;

            UdpClient localUdpClient = null;
            try
            {
                IPEndPoint localUdpPoint = new IPEndPoint(masterIp, 1000);
                localUdpClient = new UdpClient(localUdpPoint);
                localUdpClient.Client.SendTimeout = 500;
                localUdpClient.Client.ReceiveTimeout = 500;
                IPEndPoint deviceUdpPoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 1500);

                localUdpClient.Send(txCmd, txCmd.Length, deviceUdpPoint);
                byte[] recvData = localUdpClient.Receive(ref deviceUdpPoint);
                if (recvData != null)
                {
                    int br = recvData[67 + 0] + recvData[67 + 1] * 256 + recvData[67 + 2] * 256 * 256;
                    if (br != 115200)
                    {
                        return false;
                    }

                    if (recvData[67 + 51] != 3)
                    {
                        return false;
                    }

                    ipStr = recvData[12].ToString() + "." + recvData[11].ToString() + "." + recvData[10].ToString() + "." + recvData[9].ToString();
                    portStr = (recvData[67 + 12] + recvData[67 + 13] * 256).ToString();

                }
                else
                {
                    return false;
                }

                localUdpClient.Close();

                return true;
            }
            catch (Exception ex)
            {
                if (localUdpClient != null)
                {
                    localUdpClient.Close();
                }

                return false;
            }
        }

        private void comboBoxComInterface_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.comboBoxComInterface.SelectedIndex == 0)
            {
                this.comboBoxBaudrate.Enabled = true;
                this.comboBoxComPort.Enabled = true;
                this.comboBoxBaudrate.Show();
                this.comboBoxComPort.Show();
                this.labelCom.Show();
                this.labelBr.Show();

                this.labelUsbList.Enabled = false;
                this.comboBoxUsbList.Enabled = false;
                this.labelUsbList.Hide();
                this.comboBoxUsbList.Hide();

                this.groupBoxBr.Enabled = true;

                this.panelNetParams.Hide();
            }
            else if (this.comboBoxComInterface.SelectedIndex == 1)
            {
                this.comboBoxBaudrate.Enabled = false;
                this.comboBoxComPort.Enabled = false;
                this.comboBoxBaudrate.Hide();
                this.comboBoxComPort.Hide();
                this.labelCom.Hide();
                this.labelBr.Hide();

                this.groupBoxBr.Enabled = false;

                this.labelUsbList.Enabled = true;
                this.comboBoxUsbList.Enabled = true;
                this.labelUsbList.Show();
                this.comboBoxUsbList.Show();

                this.panelNetParams.Hide();
            }
            else if (this.comboBoxComInterface.SelectedIndex == 2)
            {
                this.comboBoxBaudrate.Enabled = false;
                this.comboBoxComPort.Enabled = false;
                this.comboBoxBaudrate.Hide();
                this.comboBoxComPort.Hide();
                this.labelCom.Hide();
                this.labelBr.Hide();

                this.groupBoxBr.Enabled = false;

                this.labelUsbList.Enabled = false;
                this.comboBoxUsbList.Enabled = false;
                this.labelUsbList.Hide();
                this.comboBoxUsbList.Hide();

                this.panelNetParams.Show();
            }
        }

        private void buttonOpenSerial_Click_test(object sender, EventArgs e)
        {
            if (serialDevice <= 0)
            {
                if (this.comboBoxComInterface.SelectedIndex == 0) //串口
                {
                    string portName = this.comboBoxComPort.Text;
                    if (portName.Length > 4)
                    {
                        portName = "\\\\.\\" + portName;
                    }
                    serialDevice = hfReaderDll.hfReaderOpenPort(portName, this.comboBoxBaudrate.Text);
                }
                else if (this.comboBoxComInterface.SelectedIndex == 1) //USB
                {
                    comboBoxUsbList.Items.Clear();

                    usbDevNum = hfReaderDll.hfReaderScanUsbList(hfReaderDll.HFREADER_USB_VID, hfReaderDll.HFREADER_USB_PID, usbHandleList);
                    //usbDevNum = hfReaderDll.hfReaderScanUsbList(0x1010, 0x0101, usbHandleList);
                    if (usbDevNum > 0)
                    {
                        int i = 0;
                        for (i = 0; i < usbDevNum; i++)
                        {
                            comboBoxUsbList.Items.Add("USB " + (i + 1));
                        }
                        comboBoxUsbList.SelectedIndex = 0;
                        serialDevice = usbHandleList[0];
                    }
                    else
                    {
                        serialDevice = -1;
                    }
                }
                else if (this.comboBoxComInterface.SelectedIndex == 2) //TCP
                {
                    int iPort = 0;
                    string strIp = this.comboBoxNetDeviceIpList.Text;
                    string strPort = this.comboBoxNetDevicePortList.Text;
                    if (string.IsNullOrEmpty(strIp) || string.IsNullOrEmpty(strPort))
                    {
                        MessageBox.Show("IP和端口不能为空!", "提示");
                        return;
                    }
                    iPort = int.Parse(strPort);
                    serialDevice = hfReaderDll.hfReaderOpenSocket(strIp, (ushort)iPort);
                }

                if (serialDevice > 0)
                {
                    this.buttonOpenSerial.Text = "关闭";
                    this.comboBoxComInterface.Enabled = false;
                    this.panelNetParams.Enabled = false;

                    if (this.comboBoxComInterface.SelectedIndex == 0)
                    {
                        Settings.Default.comType = "com";
                        Settings.Default.com = this.comboBoxComPort.Text;
                        Settings.Default.comBr = this.comboBoxBaudrate.Text;
                    }
                    else if (this.comboBoxComInterface.SelectedIndex == 1)
                    {
                        Settings.Default.comType = "usb";
                    }
                    else if (this.comboBoxComInterface.SelectedIndex == 2)
                    {
                        Settings.Default.comType = "net";
                        Settings.Default.netIp = comboBoxNetDeviceIpList.Text;
                        Settings.Default.netPort = comboBoxNetDevicePortList.Text;
                    }
                    Settings.Default.Save();
                }
                else
                {
                    this.Close();

                    _stopTimer.Enabled = false;
                    MessageBox.Show("打开串口失败", "提示");
                    //this.comboBoxTool.Enabled = false;
                }
            }
            else
            {
                int op = 0;
                if (this.comboBoxComInterface.SelectedIndex == 0)
                {
                    op = hfReaderDll.hfReaderClosePort(serialDevice);
                }
                else if (this.comboBoxComInterface.SelectedIndex == 1)
                {
                    int i = 0;
                    for (i = 0; i < usbDevNum; i++)
                    {
                        op = hfReaderDll.hfReaderCloseUsb(usbHandleList[i]);
                    }
                    comboBoxUsbList.Items.Clear();
                }
                else if (this.comboBoxComInterface.SelectedIndex == 2)
                {
                    op = hfReaderDll.hfReaderCloseSocket(serialDevice);
                }
                if (op >= 0)
                {
                    this.buttonOpenSerial.Text = "打开";

                }

                _recognitionTimer.Enabled = false;
                _stopTimer.Enabled = false;

                serialDevice = -1;
                this.comboBoxComInterface.Enabled = true;
                this.panelNetParams.Enabled = true;
                //this.comboBoxTool.Enabled = false;
                groupBoxCmdMode.Enabled = true;
                groupBoxTagQuit.Enabled = true;
            }
        }

        private void buttonConfigReader_Click(object sender, EventArgs e)
        {
            if (serialDevice < 0)
            {
                MessageBox.Show("请先打开串口");
                return;
            }

            Byte[] buffer = new Byte[255];
            ushort[] addrArray = new ushort[2];
            Byte WorkMode = 0;
            ushort ReaderAddr = 0;
            Byte cmdMode = 0;
            Byte AFICtrl = 0;
            Byte UIDSendMode = 0;
            Byte tagStatus = 0;
            Byte baudrate = 0;
            Byte BeepStatus = 0;
            Byte AFI = 0;
            HFREADER_CONFIG pReaderConfig = new HFREADER_CONFIG();
            Byte[] sendBuffer = new Byte[1024];
            Byte[] rcvBuffer = new Byte[1024];

            if (!GetDeviceAddr(addrArray))
            {
                return;
            }

            if (this.radioButtonISO15693.Checked)
            {
                WorkMode |= hfReaderDll.HFREADER_CFG_TYPE_ISO15693;
                Iso15693OpEnable();
            }


            WorkMode |= hfReaderDll.HFREADER_CFG_WM_INVENTORY;
            pReaderConfig.workMode = WorkMode;

            if (this.radioButtonCmdModeAuto.Checked)
            {
                cmdMode = hfReaderDll.HFREADER_CFG_INVENTORY_AUTO;
            }
            else
            {
                cmdMode = hfReaderDll.HFREADER_CFG_INVENTORY_TRIGGER;
            }
            pReaderConfig.cmdMode = cmdMode;

            UIDSendMode = hfReaderDll.HFREADER_CFG_UID_POSITIVE;
            pReaderConfig.uidSendMode = UIDSendMode;

            if (this.radioButtonBeepModeEnable.Checked)
            {
                BeepStatus = hfReaderDll.HFREADER_CFG_BUZZER_ENABLE;
            }
            else
            {
                BeepStatus = hfReaderDll.HFREADER_CFG_BUZZER_DISABLE;
            }


            pReaderConfig.beepStatus = BeepStatus;

            if (this.radioButtonAFIModeEnable.Checked)
            {
                AFICtrl = hfReaderDll.HFREADER_CFG_AFI_ENABLE;
            }
            else
            {
                AFICtrl = hfReaderDll.HFREADER_CFG_AFI_DISABLE;
            }
            pReaderConfig.afiCtrl = AFICtrl;

            if (this.radioButtonTagModeQuiet.Checked)
            {
                tagStatus = hfReaderDll.HFREADER_CFG_TAG_QUIET;
            }
            else
            {
                tagStatus = hfReaderDll.HFREADER_CFG_TAG_NOQUIET;
            }
            pReaderConfig.tagStatus = tagStatus;

            if (this.radioButtonBR9600.Checked)
            {
                baudrate = hfReaderDll.HFREADER_CFG_BAUDRATE9600;
            }
            else if (this.radioButtonBR115200.Checked)
            {
                baudrate = hfReaderDll.HFREADER_CFG_BAUDRATE115200;
            }
            else
            {
                baudrate = hfReaderDll.HFREADER_CFG_BAUDRATE38400;
            }
            pReaderConfig.baudrate = baudrate;

            if (GetHexInput(this.textBoxAFI.Text, buffer, 1) > 0)
            {
                AFI = buffer[0];
            }
            else
            {
                return;
            }
            pReaderConfig.afi = AFI;

            if (GetHexInput(this.textBoxReaderAddr.Text, buffer, 2) > 0)
            {
                ReaderAddr = (ushort)(buffer[0] * 256 + buffer[1]);
            }
            else
            {
                return;
            }
            pReaderConfig.readerAddr = ReaderAddr;

            int rlt = hfReaderDll.hfReaderSetConfig(serialDevice, addrArray[0], addrArray[1], ref pReaderConfig, sendBuffer, rcvBuffer);
            DisplayOpResult(pReaderConfig.result);
            DisplayRcvInf(rcvBuffer, "设置读写器配置参数返回<<");
            DisplaySendInf(sendBuffer, "设置读写器配置参数>>");
        }

        private void buttonReadConfiguration_Click(object sender, EventArgs e)
        {
            if (serialDevice < 0)
            {
                MessageBox.Show("请先打开串口");
                return;
            }

            Byte[] buffer = new Byte[255];
            ushort[] addrArray = new ushort[2];

            HFREADER_CONFIG pReaderConfig = new HFREADER_CONFIG();
            Byte[] sendBuffer = new Byte[1024];
            Byte[] rcvBuffer = new Byte[1024];

            if (!GetDeviceAddr(addrArray))
            {
                return;
            }

            int rlt = hfReaderDll.hfReaderGetConfig(serialDevice, addrArray[0], addrArray[1], ref pReaderConfig, sendBuffer, rcvBuffer);
            if (rlt > 0)
            {
                DisplayOpResult(pReaderConfig.result);
                {
                    Byte mode = (Byte)(pReaderConfig.workMode);
                    if ((mode & hfReaderDll.HFREADER_CFG_TYPE_MASK) == hfReaderDll.HFREADER_CFG_TYPE_ISO15693)
                    {
                        this.radioButtonISO15693.Checked = true;
                        Iso15693OpEnable();
                    }


                    if (groupBoxCmdMode.Enabled) //允许修改命令模式-中远距离
                    {
                        if (pReaderConfig.cmdMode == hfReaderDll.HFREADER_CFG_INVENTORY_AUTO)
                        {
                            this.radioButtonCmdModeAuto.Checked = true;
                        }
                        else
                        {
                            this.radioButtonCmdModeTrigle.Checked = true;
                        }
                    }

                    if ((pReaderConfig.beepStatus & 0x01) == hfReaderDll.HFREADER_CFG_BUZZER_ENABLE)
                    {
                        this.radioButtonBeepModeEnable.Checked = true;
                    }
                    else
                    {
                        this.radioButtonBeepModeDisable.Checked = true;
                    }

                    if (pReaderConfig.afiCtrl == hfReaderDll.HFREADER_CFG_AFI_ENABLE)
                    {
                        this.radioButtonAFIModeEnable.Checked = true;
                    }
                    else
                    {
                        this.radioButtonAFIModeDisable.Checked = true;
                    }

                    if (groupBoxTagQuit.Enabled)        //允许修改标签控制-中远距离
                    {
                        if (pReaderConfig.tagStatus == hfReaderDll.HFREADER_CFG_TAG_QUIET)
                        {
                            this.radioButtonTagModeQuiet.Checked = true;
                        }
                        else
                        {
                            this.radioButtonTagModeUnquiet.Checked = true;
                        }
                    }

                    if (pReaderConfig.baudrate == hfReaderDll.HFREADER_CFG_BAUDRATE9600)
                    {
                        this.radioButtonBR9600.Checked = true;
                    }
                    else if (pReaderConfig.baudrate == hfReaderDll.HFREADER_CFG_BAUDRATE115200)
                    {
                        this.radioButtonBR115200.Checked = true;
                    }
                    else
                    {
                        this.radioButtonBR38400.Checked = true;
                    }

                    this.textBoxReaderAddr.Text = pReaderConfig.readerAddr.ToString("X").PadLeft(4, '0');
                    this.textBoxAFI.Text = pReaderConfig.afi.ToString("X").PadLeft(2, '0');
                }
            }
            DisplayRcvInf(rcvBuffer, "读取读写器配置参数返回<<");
            DisplaySendInf(sendBuffer, "读取读写器配置参数>>");
        }

        public void DisplayOpResult(HFREADER_OPRESULT result)
        {
            if (result.flag == 0)
            {
                this.textBoxInf.Text = "<操作成功>\r\n\r\n" + this.textBoxInf.Text;
            }
            else
            {
                if (result.errType == 4)
                {
                    this.textBoxInf.Text = "<操作失败：参数错误或设备不支持该命令>\r\n\r\n" + this.textBoxInf.Text;
                }
                else if (result.errType == 3)
                {
                    this.textBoxInf.Text = "<操作失败：标签无响应>\r\n\r\n" + this.textBoxInf.Text;
                }
                else if (result.errType == 2)
                {
                    this.textBoxInf.Text = "<操作失败：标签响应帧校验错误>\r\n\r\n" + this.textBoxInf.Text;
                }
                else if (result.errType == 1)
                {
                    this.textBoxInf.Text = "<操作失败：标签错误>\r\n\r\n" + this.textBoxInf.Text;
                }
                else
                {
                    this.textBoxInf.Text = "<操作失败>\r\n\r\n" + this.textBoxInf.Text;
                }
            }
        }

        public void DisplaySendInf(Byte[] pSendBuf, String cmdNmae)
        {
            String text = this.textBoxInf.Text;
            int i = 0;
            int len = pSendBuf[2] + 3;
            if (pSendBuf[2] == 0)
            {
                len = 13 + pSendBuf[9] + pSendBuf[10] * 256;
            }
            String s = cmdNmae;
            for (i = 0; i < len; i++)
            {
                s += pSendBuf[i].ToString("X").PadLeft(2, '0');
                s += " ";
            }
            s += "\r\n";
            this.textBoxInf.Text = s + text;
        }

        public void DisplayRcvInf(Byte[] pRcvBuf, String cmdNmae)
        {
            String text = this.textBoxInf.Text;
            int i = 0;
            int len = pRcvBuf[2] + 3;
            if (pRcvBuf[2] == 0)
            {
                len = 14 + pRcvBuf[10] + pRcvBuf[11] * 256;
            }

            String s = cmdNmae;
            if (pRcvBuf[0] == 0x7E && pRcvBuf[1] == 0x55)
            {
                for (i = 0; i < len; i++)
                {
                    s += pRcvBuf[i].ToString("X").PadLeft(2, '0');
                    s += " ";
                }
            }
            else
            {
                s += "\r\n<通信失败>\r\n";
            }
            s += "\r\n";
            this.textBoxInf.Text = s + text;
        }
        private void Iso15693OpEnable()
        {
            this.groupBoxIso15693Op.Enabled = true;


            this.comboBox15693MemOp.SelectedIndex = 0;
            this.comboBox15693DirCmdSel.SelectedIndex = 0;
            this.comboBox15693DirMode.SelectedIndex = 0;
            this.comboBox15693AntSel.SelectedIndex = 0;
            this.comboBox15693SingleAnt.SelectedIndex = 0;

            this.textBox15693DirBlkAddr.Enabled = false;
            this.comboBox15693AntSel.Enabled = false;
            this.textBox15693MulAnt.Hide();
            this.comboBox15693SingleAnt.Show();
        }

        private void comboBox15693MemOp_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.comboBox15693MemOp.SelectedIndex == 1 || this.comboBox15693MemOp.SelectedIndex == 3
                || this.comboBox15693MemOp.SelectedIndex == 4 || this.comboBox15693MemOp.SelectedIndex == 5
                || this.comboBox15693MemOp.SelectedIndex == 6)
            {
                this.textBox15693MemValue.Enabled = false;
            }
            else
            {
                this.textBox15693MemValue.Enabled = true;
            }
        }

        private void comboBox15693DirCmdSel_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.comboBox15693DirCmdSel.SelectedIndex == 0)
            {
                this.comboBox15693AntSel.Enabled = false;
                this.textBox15693MulAnt.Enabled = false;
                this.comboBox15693SingleAnt.Enabled = false;
            }
            else
            {
                this.comboBox15693AntSel.Enabled = true;
                this.textBox15693MulAnt.Enabled = true;
                this.comboBox15693SingleAnt.Enabled = true;
            }
        }

        private void comboBox15693DirMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.comboBox15693DirMode.SelectedIndex == 1 || this.comboBox15693DirMode.SelectedIndex == 2)
            {
                this.textBox15693DirBlkAddr.Enabled = true;
                if (this.comboBox15693DirMode.SelectedIndex == 2)
                {
                    if (this.comboBox15693DirCmdSel.SelectedIndex == 0)
                    {
                        int tagNum = 0;
                        long t = 0;
                        ushort[] addrArray = new ushort[2];
                        string sInfo = "", sResult = "";

                        if (!GetDeviceAddr(addrArray))
                        {
                            return;
                        }

                        this.textBox15693DirInf.Clear();
                        sInfo = DirReadTagUid(addrArray, ref opTagUid, ref opTagUidNum, ref t);
                        sResult = "待写入标签:" + opTagUidNum.ToString() + "枚\r\n";
                        this.textBox15693DirInf.Text = sResult + sInfo;
                    }
                }
            }
            else
            {
                this.textBox15693DirBlkAddr.Enabled = false;
            }
        }

        private void comboBox15693AntSel_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.comboBox15693AntSel.SelectedItem.ToString() != "多天线")
            {
                this.comboBox15693SingleAnt.Show();
                this.textBox15693MulAnt.Hide();
            }
            else
            {
                this.comboBox15693SingleAnt.Hide();
                this.textBox15693MulAnt.Show();
            }
        }
        private string DirReadTagUid(ushort[] addr, ref Byte[] tagUid, ref int tagNum, ref long delay)
        {
            String sList = "";
            Byte[] rcvBuffer = new Byte[4096];
            Byte[] sendBuffer = new Byte[4096];
            Byte[] blockAddr = new Byte[8];
            Byte[] block = new Byte[1024];
            int rlt = 0;
            Stopwatch sw = new Stopwatch();

            sw.Start();
            rlt = hfReaderDll.iso15693OpTagsRUidAndBlock(serialDevice, addr[0], addr[1], blockAddr, 0, tagUid, block, sendBuffer, rcvBuffer);
            sw.Stop();

            delay = sw.ElapsedMilliseconds;
            this.textBoxInf.Clear();
            if (rlt > 0)
            {
                tagNum = rlt / hfReaderDll.HFREADER_ISO15693_SIZE_UID;
                int i = 0, j = 0;
                string sUid = "";

                for (i = 0; i < tagNum; i++)
                {
                    sUid = "     ";
                    for (j = 0; j < hfReaderDll.HFREADER_ISO15693_SIZE_UID; j++)
                    {
                        sUid += tagUid[i * hfReaderDll.HFREADER_ISO15693_SIZE_UID + hfReaderDll.HFREADER_ISO15693_SIZE_UID - 1 - j].ToString("X").PadLeft(2, '0');
                    }

                    sList += sUid + "\r\n";
                }
            }
            else
            {
                tagNum = 0;
            }

            if (rcvBuffer[0] == 0x7E && rcvBuffer[1] == 0x55)
            {
                this.textBoxInf.Text = "<操作成功>\r\n\r\n" + this.textBoxInf.Text;
            }

            DisplayRcvInf(rcvBuffer, "直接读取UID返回<<");
            DisplaySendInf(sendBuffer, "直接读取UID>>");

            return sList;
        }

        private string DirReadTagUidAndBlock(ushort[] addr, Byte[] blockAddr, int blockNum, ref int tagNum, ref long delay)
        {
            String sList = "";
            Byte[] rcvBuffer = new Byte[4096];
            Byte[] sendBuffer = new Byte[4096];
            Byte[] tagUid = new Byte[8 * 256];
            Byte[] block = new Byte[1024];
            int rlt = 0;
            Stopwatch sw = new Stopwatch();

            sw.Start();
            rlt = hfReaderDll.iso15693OpTagsRUidAndBlock(serialDevice, addr[0], addr[1], blockAddr, (Byte)blockNum, tagUid, block, sendBuffer, rcvBuffer);
            sw.Stop();

            delay = sw.ElapsedMilliseconds;
            this.textBoxInf.Clear();
            if (rlt > 0)
            {
                tagNum = rlt / hfReaderDll.HFREADER_ISO15693_SIZE_UID;
                int i = 0, j = 0;
                string sUid = "";
                string sBlock = "";

                for (i = 0; i < tagNum; i++)
                {
                    sUid = "     ";
                    sBlock = "      ";
                    for (j = 0; j < hfReaderDll.HFREADER_ISO15693_SIZE_UID; j++)
                    {
                        sUid += tagUid[i * hfReaderDll.HFREADER_ISO15693_SIZE_UID + hfReaderDll.HFREADER_ISO15693_SIZE_UID - 1 - j].ToString("X").PadLeft(2, '0');
                    }

                    for (j = 0; j < hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK * blockNum; j++)
                    {
                        sBlock += block[i * hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK * blockNum + j].ToString("X").PadLeft(2, '0');
                    }

                    sList += sUid + sBlock + "\r\n";
                }
            }
            else
            {
                tagNum = 0;
            }

            if (rcvBuffer[0] == 0x7E && rcvBuffer[1] == 0x55)
            {
                this.textBoxInf.Text = "<操作成功>\r\n\r\n" + this.textBoxInf.Text;
            }

            DisplayRcvInf(rcvBuffer, "直接读取数据块和UID返回<<");
            DisplaySendInf(sendBuffer, "直接读取数据块和UID>>");

            return sList;
        }



        private string ImOpReadTag(ushort[] addr, ref ISO15693_IMOP iso15693ImOp, ref long delay)
        {
            string sList = "";
            int rlt = 0;

            Byte[] rcvBuffer = new Byte[4096];
            Byte[] sendBuffer = new Byte[4096];

            Stopwatch sw = new Stopwatch();
            sw.Start();

            //获取UID
            iso15693ImOp.timeout = 10000;
            iso15693ImOp.tagNum = 0;
            iso15693ImOp.tagQuite = 0;
            rlt = hfReaderDll.iso15693ImOp(serialDevice, addr[0], addr[1], ref iso15693ImOp, sendBuffer, rcvBuffer);

            sw.Stop();
            delay = sw.ElapsedMilliseconds;

            this.textBoxInf.Clear();
            #region UID
            if (rlt > 0)
            {
                int i = 0, j = 0;
                string sUid = "", sBlock = "";
                for (i = 0; i < iso15693ImOp.tagNum; i++)
                {
                    sUid = "     ";
                    sBlock = "     ";
                    for (j = 0; j < hfReaderDll.HFREADER_ISO15693_SIZE_UID; j++)
                    {
                        sUid += iso15693ImOp.uid[i * hfReaderDll.HFREADER_ISO15693_SIZE_UID + hfReaderDll.HFREADER_ISO15693_SIZE_UID - 1 - j].ToString("X").PadLeft(2, '0');
                    }

                    for (j = 0; j < hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK * iso15693ImOp.blockNum; j++)
                    {
                        sBlock += iso15693ImOp.block[i * hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK * iso15693ImOp.blockNum + j].ToString("X").PadLeft(2, '0');
                    }

                    sList += sUid + sBlock + "\r\n";
                }
            }
            #endregion

            if (rcvBuffer[0] == 0x7E && rcvBuffer[1] == 0x55)
            {
                this.textBoxInf.Text = "<操作成功>\r\n\r\n" + this.textBoxInf.Text;
            }

            DisplayRcvInf(rcvBuffer, "IM操作返回<<");
            DisplaySendInf(sendBuffer, "IM操作>>");

            return sList;
        }

        private string ImOpWriteTagBlock(ushort[] addr, ref ISO15693_IMOP iso15693ImOp, ref long delay)
        {
            string sList = "";
            int rlt = 0;
            int i = 0, j = 0;
            int opOkTagNum = 0;
            Stopwatch sw = new Stopwatch();

            Byte[] rcvBuffer = new Byte[4096];
            Byte[] sendBuffer = new Byte[4096];

            for (i = 0; i < iso15693ImOp.tagNum; i++)
            {
                iso15693ImOp.opBlockResult[i] = 0;
                for (j = 0; j < hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK * iso15693ImOp.blockNum; j++)
                {
                    iso15693ImOp.block[i * hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK * iso15693ImOp.blockNum + j] = (Byte)(iso15693ImOp.tagNum + j + i);
                }
            }
            iso15693ImOp.result.flag = 0;
            iso15693ImOp.result.errType = 0;

            sw.Start();

            iso15693ImOp.timeout = 10000;
            iso15693ImOp.tagQuite = 0;
            rlt = hfReaderDll.iso15693ImOpWBlocks(serialDevice, addr[0], addr[1], ref iso15693ImOp, sendBuffer, rcvBuffer);

            sw.Stop();
            delay = sw.ElapsedMilliseconds;

            this.textBoxInf.Clear();
            if (rlt > 0)
            {
                string sUid = "", sBlock = "", sTagResult = "";
                for (i = 0; i < iso15693ImOp.tagNum; i++)
                {
                    sUid = "     ";
                    sBlock = "     ";
                    sTagResult = "     ";
                    for (j = 0; j < hfReaderDll.HFREADER_ISO15693_SIZE_UID; j++)
                    {
                        sUid += iso15693ImOp.uid[i * hfReaderDll.HFREADER_ISO15693_SIZE_UID + hfReaderDll.HFREADER_ISO15693_SIZE_UID - 1 - j].ToString("X").PadLeft(2, '0');
                    }
                    for (j = 0; j < hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK * iso15693ImOp.blockNum; j++)
                    {
                        sBlock += iso15693ImOp.block[i * hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK * iso15693ImOp.blockNum + j].ToString("X").PadLeft(2, '0');
                    }
                    if (iso15693ImOp.opBlockResult[i] == 1)
                    {
                        opOkTagNum++;
                    }
                    sTagResult += iso15693ImOp.opBlockResult[i].ToString();
                    sList = sUid + sBlock + sTagResult + "\r\n";
                }
            }
            if (rcvBuffer[0] == 0x7E && rcvBuffer[1] == 0x55)
            {
                this.textBoxInf.Text = "<操作成功>\r\n\r\n" + this.textBoxInf.Text;
            }

            DisplayRcvInf(rcvBuffer, "IM操作返回<<");
            DisplaySendInf(sendBuffer, "IM操作>>");

            return sList;
        }
        private string DirWriteBlock(ushort[] addr, Byte[] uid, int tagNum, Byte[] blockAddr, int blockNum, ref long delay)
        {
            string sList = "";
            Stopwatch sw = new Stopwatch();
            Byte[] rcvBuffer = new Byte[4096];
            Byte[] sendBuffer = new Byte[4096];
            Byte[] block = new Byte[tagNum * blockNum * 4];
            Byte[] result = new Byte[tagNum * blockNum];

            int i = 0, j = 0;
            for (i = 0; i < tagNum; i++)
            {
                for (j = 0; j < blockNum; j++)
                {
                    directOpTimer++;
                    block[(i * blockNum + j) * hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK + 0] = (Byte)((directOpTimer >> 0) & 0xFF);
                    block[(i * blockNum + j) * hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK + 1] = (Byte)((directOpTimer >> 8) & 0xFF);
                    block[(i * blockNum + j) * hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK + 2] = (Byte)((directOpTimer >> 16) & 0xFF);
                    block[(i * blockNum + j) * hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK + 3] = (Byte)((directOpTimer >> 24) & 0xFF);
                }
            }

            sw.Start();
            int rlt = hfReaderDll.iso15693OpTagsWriteBlock(serialDevice, addr[0], addr[1], 3000, 9000, (byte)tagNum, uid, (byte)blockNum, blockAddr, block, result, sendBuffer, rcvBuffer);
            sw.Stop();
            delay = sw.ElapsedMilliseconds;

            this.textBox15693DirInf.Clear();
            if (rlt > 0)
            {
                string sUid = "", sBlock = "", sResult = "";
                for (i = 0; i < tagNum; i++)
                {
                    sUid = "     ";
                    sBlock = "     ";
                    sResult = "     ";
                    for (j = 0; j < hfReaderDll.HFREADER_ISO15693_SIZE_UID; j++)
                    {
                        sUid += uid[i * hfReaderDll.HFREADER_ISO15693_SIZE_UID + hfReaderDll.HFREADER_ISO15693_SIZE_UID - 1 - j].ToString("X").PadLeft(2, '0');
                    }
                    for (j = 0; j < blockNum; j++)
                    {
                        sResult += result[i * blockNum + j].ToString("X").PadLeft(1);
                    }
                    for (j = 0; j < hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK * blockNum; j++)
                    {
                        sBlock += block[i * hfReaderDll.HFREADER_ISO15693_SIZE_BLOCK * blockNum + j].ToString("X").PadLeft(2, '0');
                    }
                    sList += sUid + sBlock + sResult + "\r\n";
                }
            }
            else
            {
                tagNum = 0;
            }
            if (rcvBuffer[0] == 0x7E && rcvBuffer[1] == 0x55)
            {
                this.textBoxInf.Text = "<操作成功>\r\n\r\n" + this.textBoxInf.Text;
            }

            DisplayRcvInf(rcvBuffer, "直接写数据块返回<<");
            DisplaySendInf(sendBuffer, "直接写数据块>>");

            return sList;
        }

        private void buttonDirInfClr_Click(object sender, EventArgs e)
        {
            this.textBox15693DirInf.Clear();
        }
        #endregion


        #region 感应器
        // 新增：定义连接类型枚举（便于日志区分，避免硬编码索引）
        private enum ConnectionType
        {
            None = -1,   // 无连接
            SerialPort = 0,  // 串口
            Usb = 1,         // USB
            Tcp = 2          // 网络TCP
        }


       
        /// <summary>
        /// 自动启动主流程（重构原HFReader_Shown，支持步骤跟踪与自检）
        /// </summary>
        private async Task AutoStartSequence()
        {
            try
            {
              
                // 步骤1：执行自检程序
                _currentAutoStep = AutoStartStep.SelfTest;
                if (!RunSelfTest())
                {
                    //ShowAutoCloseMessage($"自检失败：{_selfTestErrorMsg}\n自动启动终止");
                    //MessageBox.Show($"自检失败：{_selfTestErrorMsg}\n自动启动终止", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    _currentAutoStep = AutoStartStep.Failed;
                    return;
                }
                Console.WriteLine("自检通过，开始自动启动流程...");

                // 步骤2：打开串口
                _currentAutoStep = AutoStartStep.OpenSerial;
                if (!await ExecuteStepWithRetry(
                    stepAction: async () => await TryOpenSerial(),
                    stepName: "打开串口"))
                {
                    _currentAutoStep = AutoStartStep.Failed;
                    return;
                }
               

                // 步骤3：配置阅读器
                _currentAutoStep = AutoStartStep.ConfigReader;
                if (!await ExecuteStepWithRetry(
                    stepAction: async () => await TryConfigReader(),
                    stepName: "配置阅读器"))
                {
                    _currentAutoStep = AutoStartStep.Failed;
                    return;
                }

                // 步骤4：读取配置
                _currentAutoStep = AutoStartStep.ReadConfig;
                if (!await ExecuteStepWithRetry(
                    stepAction: async () => await TryReadConfig(),
                    stepName: "读取配置"))
                {
                    _currentAutoStep = AutoStartStep.Failed;
                    return;
                }

                // 步骤5：切换到ISO15693页面
                _currentAutoStep = AutoStartStep.SwitchTab15693;
                try
                {
                    await Task.Delay(2000); // 等待UI响应
                    if (!tabControlDevice.TabPages.ContainsKey("tabPage2"))
                    {
                        throw new Exception("未找到ISO15693页面（tabPage2）");
                    }
                    tabControlDevice.SelectTab("tabPage2");
                    Console.WriteLine("已切换到ISO15693页面");
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"切换ISO15693页面失败：{ex.Message}", "错误");
                    _currentAutoStep = AutoStartStep.Failed;
                    return;
                }

                // 步骤6：切换到操作标签页面
                _currentAutoStep = AutoStartStep.SwitchTabOperate;
                try
                {
                    await Task.Delay(1000); // 等待页面加载
                    if (!tabControlIso15693.TabPages.ContainsKey("tabPage4"))
                    {
                        throw new Exception("未找到操作标签页面（tabPage4）");
                    }
                    tabControlIso15693.SelectTab("tabPage4");
                    Console.WriteLine("已切换到操作标签页面");
                }
                catch (Exception ex)
                {
                    //MessageBox.Show($"切换操作标签页面失败：{ex.Message}", "错误");
                    //ShowAutoCloseMessage($"切换操作标签页面失败：{ex.Message} ");
                    _currentAutoStep = AutoStartStep.Failed;
                    return;
                }

                // 步骤7：执行标签操作（启动循环扫描）
                _currentAutoStep = AutoStartStep.ExecTagOp;
                if (!await ExecuteStepWithRetry(
                    stepAction: async () => await TryExecTagOperation(),
                    stepName: "执行标签操作"))
                {
                    _currentAutoStep = AutoStartStep.Failed;
                    return;
                }

                // 所有步骤完成
                _currentAutoStep = AutoStartStep.Completed;

                // ShowAutoCloseMessage("自动启动流程全部完成，已开始循环扫描");
                labelLoopStatus.Text = "自动启动完成，循环扫描中...";


                // 所有步骤完成后，延迟几秒钟自动隐藏程序
                await Task.Delay(1000); // 等待隐藏
                this.Hide(); // 隐藏窗体，实例仍在内存中
                Console.Write("自动启动完成，隐藏程序中...");

            }
            catch (Exception ex)
            {
                MessageBox.Show($"自动启动异常：{ex.Message}\n当前步骤：{_currentAutoStep}", "错误");
                _currentAutoStep = AutoStartStep.Failed;
            }
        }

 

        /// <summary>
        /// 点击打开按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonOpenSerial_Click(object sender, EventArgs e)
        {
            // 新增：日志前缀（便于定位操作链路）
            string logPrefix = $"[串口操作] 按钮点击 | 当前serialDevice={serialDevice} | 连接类型={comboBoxComInterface.SelectedIndex}";
            Console.WriteLine($"{logPrefix} | 开始执行操作");

            try
            {
                // -------------------------- 打开逻辑（serialDevice <= 0 表示未打开）--------------------------
                if (serialDevice <= 0)
                {
                    ConnectionType connType = (ConnectionType)comboBoxComInterface.SelectedIndex;
                    Console.WriteLine($"{logPrefix} | 执行【打开】操作 | 连接类型：{connType}");

                    // 1. 按连接类型分支处理（新增前置校验+详细日志）
                    switch (connType)
                    {
                        case ConnectionType.SerialPort: // 串口连接
                            HandleSerialPortOpen(logPrefix);
                            break;

                        case ConnectionType.Usb: // USB连接
                            HandleUsbOpen(logPrefix);
                            break;

                        case ConnectionType.Tcp: // TCP连接
                            HandleTcpOpen(logPrefix);
                            break;

                        default:
                            string unknownErr = $"未知连接类型（索引：{comboBoxComInterface.SelectedIndex}）";
                            MessageBox.Show($"打开失败：{unknownErr}", "错误");
                            Console.WriteLine($"{logPrefix} | 打开失败：{unknownErr}");
                            return;
                    }

                    // 2. 打开结果统一处理（新增状态判断+日志）
                    if (serialDevice > 0)
                    {
                        // 新增：将当前连接类型记录到全局变量（关键！）
                        _currentConnType = connType;

                        // 打开成功：更新UI+保存配置（原有逻辑保留）
                        UpdateUiAfterOpenSuccess(connType);
                        Console.WriteLine($"{logPrefix} | 打开成功 | serialDevice={serialDevice} | 连接类型：{connType} | 已更新全局_currentConnType");
                    }
                    else
                    {


                        // 打开失败：强化错误处理（原有逻辑保留）
                        HandleOpenFailure(connType, logPrefix);

                        // 新增：打开失败，重置全局连接类型为“无连接”
                        _currentConnType = ConnectionType.None;
                        Console.WriteLine($"{logPrefix} | 打开失败，已重置全局_currentConnType=None");
                    }
                }
                // -------------------------- 关闭逻辑（serialDevice > 0 表示已打开）--------------------------
                else
                {
                    ConnectionType connType = (ConnectionType)comboBoxComInterface.SelectedIndex;
                    Console.WriteLine($"{logPrefix} | 执行【关闭】操作 | 连接类型：{connType}");

                    // 调用对应关闭SDK接口（原有逻辑保留）
                    int closeResult = CloseConnectionByType(connType);

                    if (closeResult >= 0)
                    {

                        // 关闭成功：重置UI+状态（原有逻辑保留）
                        UpdateUiAfterCloseSuccess(connType);
                        Console.WriteLine($"{logPrefix} | 关闭成功 | 连接类型：{connType} | SDK返回值：{closeResult}");
                    }
                    else
                    {
                        // 关闭失败：提示用户+强制重置状态（原有逻辑保留）
                        string closeErr = $"关闭{connType}失败（SDK返回值：{closeResult}）...";
                        MessageBox.Show(closeErr, "警告");
                        Console.WriteLine($"{logPrefix} | 关闭失败 | {closeErr}");
                        ForceResetConnectionState(connType);
                    }

                    // 新增：无论关闭成功/失败，均重置全局连接类型为“无连接”
                    _currentConnType = ConnectionType.None;
                    Console.WriteLine($"{logPrefix} | 关闭流程结束，已重置全局_currentConnType=None");
                }
            }
            catch (Exception ex)
            {
                // 新增：捕获所有异常，避免程序崩溃+详细日志
                string exMsg = $"操作异常：{ex.Message} | 堆栈：{ex.StackTrace}";
                MessageBox.Show($"串口操作出错：{ex.Message}", "错误");
                Console.WriteLine($"{logPrefix} | {exMsg}");

                // 异常后强制重置状态（关键：防止异常导致状态混乱）
                ForceResetConnectionState((ConnectionType)comboBoxComInterface.SelectedIndex);
            }
        }

        // -------------------------- 新增：串口打开专属处理（含前置校验+详细日志）--------------------------
        private void HandleSerialPortOpen(string logPrefix)
        {

            string portName = comboBoxComPort.Text;
            string baudRate = comboBoxBaudrate.Text;


            // 前置校验1：端口号不能为空
            if (string.IsNullOrWhiteSpace(portName))
            {
                throw new ArgumentException("串口端口号不能为空（如COM3）");
            }
            // 前置校验2：波特率不能为空
            if (string.IsNullOrWhiteSpace(baudRate))
            {
                throw new ArgumentException("串口波特率不能为空（如38400）");
            }

            // 处理特殊端口号（如COM10+，需加\\\\.\\前缀）
            if (portName.Length > 4)
            {
                portName = "\\\\.\\" + portName;
                Console.WriteLine($"{logPrefix} | 串口端口号超长，自动补充前缀：{portName}");
            }

            // 调用SDK打开串口（记录参数+返回值）
            Console.WriteLine($"{logPrefix} | 调用SDK打开串口 | 端口：{portName} | 波特率：{baudRate}");
            serialDevice = hfReaderDll.hfReaderOpenPort(portName, baudRate);
            Console.WriteLine($"{logPrefix} | SDK打开串口返回值：{serialDevice}");
        }

        // -------------------------- 新增：USB打开专属处理（含设备扫描校验+日志）--------------------------
        private void HandleUsbOpen(string logPrefix)
        {
            // 清空旧设备列表（避免残留）
            comboBoxUsbList.Items.Clear();
            usbDevNum = 0; // 重置设备数量（避免旧值干扰）
            Array.Clear(usbHandleList, 0, usbHandleList.Length); // 清空设备句柄数组

            // 调用SDK扫描USB设备（记录扫描结果）
            Console.WriteLine($"{logPrefix} | 调用SDK扫描USB设备 | VID={hfReaderDll.HFREADER_USB_VID} | PID={hfReaderDll.HFREADER_USB_PID}");
            usbDevNum = hfReaderDll.hfReaderScanUsbList(hfReaderDll.HFREADER_USB_VID, hfReaderDll.HFREADER_USB_PID, usbHandleList);
            Console.WriteLine($"{logPrefix} | SDK扫描USB返回设备数：{usbDevNum}");

            // 校验扫描结果
            if (usbDevNum <= 0)
            {
                serialDevice = -1;
                throw new Exception($"USB设备扫描失败（无可用设备，SDK返回设备数：{usbDevNum}），请检查USB连接或设备电源");
            }

            // 填充设备列表+选择第一个设备
            for (int i = 0; i < usbDevNum; i++)
            {
                comboBoxUsbList.Items.Add($"USB {i + 1}（句柄：{usbHandleList[i]}）"); // 显示句柄，便于排查
                Console.WriteLine($"{logPrefix} | 发现USB设备：索引{i} | 句柄：{usbHandleList[i]}");
            }
            comboBoxUsbList.SelectedIndex = 0;
            serialDevice = usbHandleList[0]; // 取第一个设备句柄
        }

        // -------------------------- 新增：TCP打开专属处理（含IP/端口校验+格式容错）--------------------------
        private void HandleTcpOpen(string logPrefix)
        {
            string ip = comboBoxNetDeviceIpList.Text;
            string portStr = comboBoxNetDevicePortList.Text;
            int port = 0;

            // 前置校验1：IP/端口不能为空
            if (string.IsNullOrWhiteSpace(ip))
            {
                throw new ArgumentException("TCP连接IP地址不能为空");
            }
            if (string.IsNullOrWhiteSpace(portStr))
            {
                throw new ArgumentException("TCP连接端口号不能为空");
            }

            // 前置校验2：端口号格式正确（避免非数字导致崩溃）
            if (!int.TryParse(portStr, out port) || port < 1 || port > 65535)
            {
                throw new ArgumentException($"TCP端口号格式错误（{portStr}），请输入1-65535之间的整数");
            }

            // 调用SDK打开TCP连接（记录参数）
            Console.WriteLine($"{logPrefix} | 调用SDK打开TCP连接 | IP：{ip} | 端口：{port}");
            serialDevice = hfReaderDll.hfReaderOpenSocket(ip, (ushort)port);
            Console.WriteLine($"{logPrefix} | SDK打开TCP返回值：{serialDevice}");
        }

        // -------------------------- 新增：打开成功后UI/配置更新（统一逻辑）--------------------------
        private void UpdateUiAfterOpenSuccess(ConnectionType connType)
        {
            buttonOpenSerial.Text = "关闭";
            comboBoxComInterface.Enabled = false;
            panelNetParams.Enabled = false;

            // 保存配置（保留原逻辑，新增日志）
            switch (connType)
            {
                case ConnectionType.SerialPort:
                    Settings.Default.comType = "com";
                    Settings.Default.com = comboBoxComPort.Text;
                    Settings.Default.comBr = comboBoxBaudrate.Text;
                    Console.WriteLine($"[配置保存] 串口配置 | COM：{Settings.Default.com} | 波特率：{Settings.Default.comBr}");
                    break;
                case ConnectionType.Usb:
                    Settings.Default.comType = "usb";
                    Console.WriteLine($"[配置保存] USB配置");
                    break;
                case ConnectionType.Tcp:
                    Settings.Default.comType = "net";
                    Settings.Default.netIp = comboBoxNetDeviceIpList.Text;
                    Settings.Default.netPort = comboBoxNetDevicePortList.Text;
                    Console.WriteLine($"[配置保存] TCP配置 | IP：{Settings.Default.netIp} | 端口：{Settings.Default.netPort}");
                    break;
            }
            Settings.Default.Save();
            Console.WriteLine($"[配置保存] 配置已写入Settings");

            // 启动识别定时器（确保打开后自动开始扫描，可选）
            if (!_recognitionTimer.Enabled)
            {
                _recognitionTimer.Start();
                Console.WriteLine($"[定时器启动] 识别定时器已启动（间隔：{_recognitionTimer.Interval}ms）");
            }
        }

        // -------------------------- 新增：打开失败后处理（避免直接关闭窗体，先清理资源）--------------------------
        private void HandleOpenFailure(ConnectionType connType, string logPrefix)
        {
            // 停止定时器（避免失败后定时器仍运行）
            _stopTimer.Enabled = false;
            _recognitionTimer.Enabled = false;
            Console.WriteLine($"{logPrefix} | 打开失败，已停止所有定时器");

            // 分类提示失败原因（比原“打开串口失败”更具体）
            string failMsg = connType switch
            {
                ConnectionType.SerialPort => $"串口打开失败（SDK返回值：{serialDevice}），可能原因：1.端口被占用 2.端口不存在 3.波特率不匹配",
                ConnectionType.Usb => $"USB设备打开失败（SDK返回值：{serialDevice}），可能原因：1.设备未授权 2.USB驱动异常",
                ConnectionType.Tcp => $"TCP连接失败（SDK返回值：{serialDevice}），可能原因：1.IP/端口错误 2.设备未联网 3.防火墙拦截",
                _ => $"打开失败（SDK返回值：{serialDevice}）"
            };
            MessageBox.Show(failMsg, "提示");
            Console.WriteLine($"{logPrefix} | 打开失败 | {failMsg}");
           
            // 强制重置状态（避免失败后serialDevice残留错误值）
            serialDevice = -1;
            Console.WriteLine($"{logPrefix} | 打开失败，已重置serialDevice=-1");

            // 原逻辑的this.Close()可注释（避免用户未看清提示就关闭，如需保留需先清理资源）
            // this.Close(); 
        }

        // -------------------------- 新增：按连接类型调用关闭SDK接口（统一逻辑）--------------------------
        private int CloseConnectionByType(ConnectionType connType)
        {
            int closeResult = -1;
            switch (connType)
            {
                case ConnectionType.SerialPort:
                    Console.WriteLine($"[关闭操作] 调用SDK关闭串口 | serialDevice={serialDevice}");
                    closeResult = hfReaderDll.hfReaderClosePort(serialDevice);
                    break;

                case ConnectionType.Usb:
                    // 关闭所有扫描到的USB设备（避免漏关）
                    closeResult = 0; // 默认为成功，有一个失败则整体失败
                    for (int i = 0; i < usbDevNum; i++)
                    {
                        Console.WriteLine($"[关闭操作] 调用SDK关闭USB设备 | 索引{i} | 句柄：{usbHandleList[i]}");
                        int singleCloseResult = hfReaderDll.hfReaderCloseUsb(usbHandleList[i]);
                        if (singleCloseResult < 0)
                        {
                            closeResult = singleCloseResult; // 记录第一个失败的返回值
                            Console.WriteLine($"[关闭操作] USB设备{i}关闭失败 | SDK返回值：{singleCloseResult}");
                        }
                        else
                        {
                            Console.WriteLine($"[关闭操作] USB设备{i}关闭成功 | SDK返回值：{singleCloseResult}");
                        }
                    }
                    break;

                case ConnectionType.Tcp:
                    Console.WriteLine($"[关闭操作] 调用SDK关闭TCP连接 | serialDevice={serialDevice}");
                    closeResult = hfReaderDll.hfReaderCloseSocket(serialDevice);
                    break;
            }
            Console.WriteLine($"[关闭操作] 关闭结果汇总 | SDK返回值：{closeResult}");
            return closeResult;
        }

        // -------------------------- 新增：关闭成功后UI/状态重置（统一逻辑）--------------------------
        private void UpdateUiAfterCloseSuccess(ConnectionType connType)
        {
            // 更新UI文本
            buttonOpenSerial.Text = "打开";

            // 重置控件状态
            comboBoxComInterface.Enabled = true;
            panelNetParams.Enabled = true;
            groupBoxCmdMode.Enabled = true;
            groupBoxTagQuit.Enabled = true;

            // 停止定时器
            _recognitionTimer.Enabled = false;
            _stopTimer.Enabled = false;
            Console.WriteLine($"[关闭成功] 已停止识别/停止定时器");

            // 重置核心状态（关键：避免下次打开残留旧值）
            serialDevice = -1;
            if (connType == ConnectionType.Usb)
            {
                comboBoxUsbList.Items.Clear();
                usbDevNum = 0;
                Array.Clear(usbHandleList, 0, usbHandleList.Length);
                Console.WriteLine($"[关闭成功] 已清空USB设备列表和句柄数组");
            }
            Console.WriteLine($"[关闭成功] 核心状态已重置 | serialDevice=-1");
        }

        // -------------------------- 新增：强制重置连接状态（异常/失败时兜底）--------------------------
        private void ForceResetConnectionState(ConnectionType connType)
        {
            // 停止所有定时器
            _recognitionTimer.Enabled = false;
            _stopTimer.Enabled = false;

            // 重置核心变量
            serialDevice = -1;
            if (connType == ConnectionType.Usb)
            {
                comboBoxUsbList.Items.Clear();
                usbDevNum = 0;
                if (usbHandleList != null) Array.Clear(usbHandleList, 0, usbHandleList.Length);
            }

            // 恢复控件状态
            comboBoxComInterface.Enabled = true;
            panelNetParams.Enabled = true;
            buttonOpenSerial.Text = "打开";

            Console.WriteLine($"[强制重置] 连接状态已兜底重置 | 连接类型：{connType} | serialDevice=-1");
        }


        /// <summary>
        /// 执行自检程序（检查控件、硬件初始化状态）
        /// </summary>
        /// <returns>自检是否通过</returns>
        private bool RunSelfTest()
        {
            // 1. 检查关键控件是否存在
            if (buttonOpenSerial == null || buttonConfigReader == null || buttonReadConfiguration == null)
            {
                _selfTestErrorMsg = "关键按钮控件未初始化（OpenSerial/ConfigReader/ReadConfig）";
                return false;
            }
            if (comboBox15693DirCmdSel == null || comboBox15693DirMode == null)
            {
                _selfTestErrorMsg = "关键下拉框控件未初始化（CmdSel/Mode）";
                return false;
            }
            if (textBox15693DirBlkAddr == null || textBox15693DirInf == null)
            {
                _selfTestErrorMsg = "关键文本框控件未初始化（BlkAddr/Inf）";
                return false;
            }

            // 2. 检查下拉框是否有默认选项（避免后续步骤因无选项报错）
            if (comboBox15693DirCmdSel.Items.Count == 0)
            {
                _selfTestErrorMsg = "操作命令下拉框（comboBox15693DirCmdSel）无选项，请先配置";
                return false;
            }
            if (comboBox15693DirMode.Items.Count == 0)
            {
                _selfTestErrorMsg = "操作模式下拉框（comboBox15693DirMode）无选项，请先配置";
                return false;
            }
            // 自动选择第一个选项（避免用户未手动选择）
            comboBox15693DirCmdSel.SelectedIndex = 0;
            comboBox15693DirMode.SelectedIndex = 0;

            // 3. 检查数据块地址文本框（模式1/2需要，提前设置默认值）
            if (string.IsNullOrWhiteSpace(textBox15693DirBlkAddr.Text))
            {
                textBox15693DirBlkAddr.Text = "0-1"; // 默认读取0、1数据块（可根据业务调整）
                Console.WriteLine("数据块地址文本框为空，已设置默认值：0-1");
            }

            // 4. 检查硬件初始化（串口设备、定时器）
            if (_recognitionTimer == null || _stopTimer == null)
            {
                _selfTestErrorMsg = "识别/停止定时器未初始化，请检查感应器处理代码";
                return false;
            }
            if (_cts == null)
            {
                _cts = new CancellationTokenSource(); // 补全初始化
                Console.WriteLine("线程取消源未初始化，已自动创建");
            }

            // 5. 检查阅读器硬件响应（发送测试命令，可选，根据硬件API调整）
            try
            {
                if (!CheckReaderResponse())
                {
                    _selfTestErrorMsg = "阅读器硬件无响应，请检查设备连接";
                    return false;
                }
            }
            catch (Exception ex)
            {
                _selfTestErrorMsg = $"硬件检查异常：{ex.Message}";
                return false;
            }

            return true;
        }


        /// <summary>
        /// 通用步骤执行工具（带重试+日志）
        /// </summary>
        /// <param name="stepAction">步骤执行逻辑</param>
        /// <param name="stepName">步骤名称（用于日志）</param>
        /// <returns>步骤是否成功</returns>
        private async Task<bool> ExecuteStepWithRetry(Func<Task<bool>> stepAction, string stepName)
        {
            int retryCount = 0;
            while (retryCount < MaxRetryCount)
            {
                try
                {
                    Console.WriteLine($"正在执行【{stepName}】，第{retryCount + 1}次尝试...");
                    if (await stepAction())
                    {
                        Console.WriteLine($"【{stepName}】执行成功");
                        return true;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"【{stepName}】尝试失败：{ex.Message}");
                }

                retryCount++;
                if (retryCount >= MaxRetryCount)
                {
                    // MessageBox.Show($"【{stepName}】失败，已达到最大重试次数（{MaxRetryCount}次）", "错误");
                    //ShowAutoCloseMessage($"【{stepName}】失败，已达到最大重试次数（{MaxRetryCount}次 ");
                    return false;
                }

                // 重试前延迟（递增延迟，避免频繁重试）
                int delayMs = 2000 * (retryCount + 1);
                Console.WriteLine($"等待{delayMs}ms后重试【{stepName}】...");
                await Task.Delay(delayMs);
            }
            return false;
        }

        /// <summary>
        /// 修复：解析原始数据，提取有效感应器ID（E开头16位，支持大小写，最多2个）
        /// 修复：强制解析E开头16位ID（支持大小写，最多2个），增加日志与干扰字符清理
        /// 传感器数据解析方法（格式化原始数据，提取有效ID）
        /// 修复：增加原始数据日志+空值判断，确保推送前数据有效
        /// <param name="rawData">硬件返回的原始数据（从SDK获取）</param>
        /// <returns>格式化后的有效传感器ID列表（最多2个）</returns>
        private List<string> ParseSensorData(string rawData)
        {
            List<string> validSensors = new List<string>(); // 存储有效传感器ID

            // 1. 打印原始数据日志（关键：排查硬件是否真的返回数据）
            Console.WriteLine($"[数据解析-输入] 重新扫描的原始数据：{rawData ?? "null"}");

            // 2. 空值判断（提前拦截空数据，避免后续推送空值）
            if (string.IsNullOrWhiteSpace(rawData))
            {
                Console.WriteLine($"[数据解析-警告] 原始数据为空（可能原因：传感器未响应、串口断开）");
                _currentSensors = validSensors; // 重置临时存储的传感器列表
                UpdateSensorUIControls(validSensors); // 清空UI上的传感器ID显示
                return validSensors;
            }

            // 3. 清理原始数据（移除非十六进制+E/e的字符，避免干扰ID识别）
            string cleanedData = Regex.Replace(rawData, @"[^0-9A-Fa-fEe]", "");
            Console.WriteLine($"[数据解析-清理后] 清理后的数据：{cleanedData}");

            // 4. 匹配有效传感器ID（规则：E开头+15位十六进制字符，共16位，支持大小写）
            const string SensorIdPattern = @"E[0-9A-Fa-f]{15}"; // 固定匹配规则（根据硬件调整）
            MatchCollection matches = Regex.Matches(cleanedData, SensorIdPattern, RegexOptions.IgnoreCase);

            // 5. 收集最多2个有效ID（统一转为大写，避免大小写不一致导致的外部处理问题）
            foreach (Match match in matches)
            {
                if (validSensors.Count < 2)
                {
                    string sensorId = match.Value.ToUpperInvariant();
                    validSensors.Add(sensorId);
                    Console.WriteLine($"[数据解析-成功] 提取有效传感器ID：{sensorId}（累计：{validSensors.Count}个）");
                }
                else
                {
                    Console.WriteLine($"[数据解析-警告] 传感器ID数量超过2个，忽略后续ID：{match.Value}");
                    break; // 最多保留2个ID（根据业务需求调整）
                }
            }

            // 6. 同步更新临时存储和UI（确保数据一致性：临时变量=UI显示=推送数据）
            _currentSensors = validSensors;
            UpdateSensorUIControls(validSensors);
          
            return validSensors;
        }

        /// <summary>
        /// 同步更新传感器ID到UI控件（避免直接在解析方法中耦合UI操作）
        /// </summary>
        private void UpdateSensorUIControls(List<string> sensors)
        {
            // 确保在UI线程操作控件
            if (InvokeRequired)
            {
                Invoke(new Action<List<string>>(UpdateSensorUIControls), sensors);
                return;
            }

            // 清空旧值
            text_SensorID1 = string.Empty;
            text_SensorID2 = string.Empty;

            // 赋值新值（1个或2个ID）
            if (sensors.Count >= 1)
            {
                text_SensorID1 = sensors[0];
            }
            if (sensors.Count >= 2)
            {
                text_SensorID2 = sensors[1];
            }

            // 日志输出当前UI值
            Console.WriteLine($"UI控件更新：text_SensorID1={text_SensorID1}, text_SensorID2={text_SensorID2}");
        }

        /// <summary>
        /// 优化：循环识别定时器触发事件（1秒/次）
        /// 核心改进：ID互换判断、重复扫描检测、与主线程状态同步
        /// 新增：单传感器“持续等待第二个”的强制循环逻辑
        /// 优化：循环识别定时器触发事件（1秒/次）
        /// 确保双传感器识别后能正确进入首次/二次分支
        /// 重新扫描核心触发点：_recognitionTimer定时器事件（10秒/次）
        /// 修复：补全"获取设备地址→执行单次识别"链路，确保重新扫描必然触发数据推送
        /// </summary>
        private void RecognitionTimer_Tick(object sender, EventArgs e)
        {
            // 停止期/未开启循环时，跳过扫描（基础保护逻辑）
            if (_isStopped || !_isLooping)
            {
                Console.WriteLine($"[重新扫描-跳过] 停止期={_isStopped}，循环状态={_isLooping}");
                return;
            }

            try
            {
                _recognitionCount++;
                Console.WriteLine($"=== 第{_recognitionCount}次重新扫描开始（10秒周期） ===");

                // 1. 获取设备地址（复用原有地址逻辑，确保地址有效才能执行识别）
                ushort[] addrArray = new ushort[2]; // 存储设备地址的数组（硬件要求格式）
                if (GetDeviceAddr(addrArray)) // 检查地址是否获取成功
                {
                    Console.WriteLine($"[重新扫描-准备] 设备地址获取成功（addrArray：{addrArray[0]},{addrArray[1]}），即将执行识别");
                    // 2. 执行单次识别（核心：此方法内部会调用DataUpdated.Invoke推送数据）
                    ExecuteSingleRecognition(addrArray);
                }
                else
                {
                    // 地址获取失败时，重置状态并打印日志（便于排查硬件问题）
                    Console.WriteLine($"[重新扫描-警告] 设备地址获取失败，无法执行识别（未推送数据）");
                    ResetRecognitionState();
                    return;
                }

                // 3. 原有传感器状态判断（识别后处理，如单/双传感器分支，保留原逻辑）
                List<string> validSensors = ParseSensorData(_tempSensor1);
                int sensorCount = validSensors.Count;
                string sensorIdsLog = sensorCount > 0 ? string.Join("、", validSensors) : "无";
                Console.WriteLine($"[重新扫描-结果] 有效传感器数量={sensorCount}，ID列表：[{sensorIdsLog}]");

                // 根据传感器数量处理状态（保留原逻辑，不影响数据推送）
                switch (sensorCount)
                {
                    case 0: HandleNoSensors(); break;
                    case 1: HandleSingleSensor(); break;
                    case 2: HandleTwoSensorsWithSwapCheck(); break;
                    default:
                        Console.WriteLine($"[重新扫描-警告] 传感器数量异常（{sensorCount}个），取前2个处理");
                        HandleTwoSensorsWithSwapCheck();
                        break;
                }

                Console.WriteLine($"=== 第{_recognitionCount}次重新扫描结束 ===\n");
            }
            catch (Exception ex)
            {
                // 异常时重置状态，避免扫描卡死，同时打印详细日志
                Console.WriteLine($"[重新扫描-异常] {ex.Message}，堆栈：{ex.StackTrace}");
                ResetRecognitionState();
            }
        }

        /// <summary>
        /// 优化：处理无传感器场景（0个ID时，重置状态但继续扫描）
        /// 区别于单传感器：无任何ID时需重置，避免旧状态干扰
        /// </summary>
        private void HandleNoSensors()
        {

            ResetRecognitionState();
            labelLoopStatus.Text = $"第{_recognitionCount}次扫描：未识别到任何传感器，继续扫描...";
            Console.WriteLine("无传感器处理：未识别到任何ID，重置状态后继续扫描");
        }

        /// <summary>
        /// 处理单传感器场景（仅更新，不判断重复）
        /// 优化：处理单传感器场景（仅识别到1个ID时，持续扫描直到获取2个）
        /// 核心：不触发重复判断，不停止循环，强制继续扫描
        /// 优化：处理单传感器场景（增加超时提示，可选）
        /// </summary>
        private void HandleSingleSensor()
        {
            // 1. 单传感器等待计数递增
            _singleSensorWaitCount++;

            // 2. 清空历史重复判断记录
            _lastConfirmedSensors.Clear();

            // 3. 超时判断（超过30秒未获取第二个ID，提示用户）
            string singleSensorId = string.IsNullOrEmpty(text_SensorID1) ? text_SensorID2 : text_SensorID1;
            if (_singleSensorWaitCount >= SingleSensorTimeoutCount)
            {
                labelLoopStatus.Text = $"第{_recognitionCount}次扫描：等待第二个传感器超时（{SingleSensorTimeoutCount}秒），当前仅识别到（{singleSensorId}）";
                Console.WriteLine($"单传感器超时警告：已等待{SingleSensorTimeoutCount}秒，未获取第二个ID，请检查硬件");
                // 可选：弹出提示框（避免频繁弹窗，建议仅日志提示）
                // if (_singleSensorWaitCount % 10 == 0) MessageBox.Show($"等待第二个传感器超时，请检查设备连接");
            }
            else
            {
                labelLoopStatus.Text = $"第{_recognitionCount}次扫描：仅识别到1个传感器（{singleSensorId}），持续等待第二个（已等待{_singleSensorWaitCount}秒）";
                Console.WriteLine($"单传感器处理：当前仅识别到1个ID（{singleSensorId}），已等待{_singleSensorWaitCount}秒，继续扫描");
            }
        }

        /// <summary>
        /// 处理双传感器场景（支持ID互换判断+重复扫描检测）
        /// 优化：处理双传感器场景（识别到2个ID时，重置单传感器等待计数）
        /// 修复：双传感器处理逻辑（含首次/二次识别标记，支持互换判断+重复停止）
        /// 核心：用_hasFirstTwoSensors区分首次/二次，确保重复识别时能触发停止10秒
        /// </summary>
        private void HandleTwoSensorsWithSwapCheck()
        {
            // 1. 强制线程安全锁（防止多线程同时修改状态）
            lock (this)
            {
                // 2. 构建当前ID集合（忽略顺序，支持互换）
                HashSet<string> currentSensorsSet = new HashSet<string>(_currentSensors, StringComparer.Ordinal);
                string currentIds = string.Join("、", _currentSensors);
                Console.WriteLine($"[双传感器处理] 当前ID：{currentIds} | 首次识别标记：{_hasFirstTwoSensors} | 历史ID：{string.Join("、", _lastConfirmedSensors)}");

                // 3. 分支1：首次识别双ID（必须保存历史+标记状态）
                if (!_hasFirstTwoSensors)
                {
                    _lastConfirmedSensors = new HashSet<string>(currentSensorsSet); // 深拷贝，避免引用问题
                    _hasFirstTwoSensors = true; // 强制标记为“已首次识别”
                    UpdateLoopStatusUI($"第{_recognitionCount}次：首次识别双ID（{currentIds}），等待二次确认");
                    Console.WriteLine($"[首次识别] 已保存历史ID：{string.Join("、", _lastConfirmedSensors)} | 标记_hasFirstTwoSensors=true");
                    return;
                }

                // 4. 分支2：二次识别双ID（强制对比+兜底触发）

                bool isSameAsLast = currentSensorsSet.SetEquals(_lastConfirmedSensors);
                Console.WriteLine($"[二次识别] 当前ID与历史是否一致：{isSameAsLast}");

                if (isSameAsLast)
                {
                    // 4.1 重复识别：强制触发暂停（增加兜底判断，防止方法未调用）
                    UpdateLoopStatusUI($"第{_recognitionCount}次：双ID重复（{currentIds}），触发10秒暂停");
                    Console.WriteLine($"[重复确认] 触发暂停逻辑！当前ID：{currentIds} | 历史ID：{string.Join("、", _lastConfirmedSensors)}");

                    // 兜底：确保SensorsConfirmed事件触发（通知外部）
                    if (SensorsConfirmed != null)
                    {
                        SensorsConfirmed.Invoke(text_SensorID1, text_SensorID2);
                    }
                    else
                    {
                        Console.WriteLine("[警告] SensorsConfirmed事件未订阅，可能影响外部通知");
                    }

                    // 强制调用暂停方法（即使有异常也会在方法内捕获）
                    StopRecognitionFor60s();
                }
                else
                {
                    // 4.2 ID更新：重置状态，重新等待首次识别
                    _lastConfirmedSensors.Clear();
                    _lastConfirmedSensors = new HashSet<string>(currentSensorsSet);
                    _hasFirstTwoSensors = false; // 强制重置标记
                    UpdateLoopStatusUI($"第{_recognitionCount}次：双ID更新（{currentIds}），重新等待二次确认");
                    Console.WriteLine($"[ID更新] 重置首次标记 | 新历史ID：{string.Join("、", _lastConfirmedSensors)}");
                }
            }
        }

        /// <summary>
        /// 线程安全的UI状态更新（专门用于更新labelLoopStatus）
        /// </summary>
        private void UpdateLoopStatusUI(string statusText)
        {
            if (labelLoopStatus == null) return;

            // 跨线程判断：若当前线程不是UI线程，通过Invoke委托更新
            if (labelLoopStatus.InvokeRequired)
            {
                labelLoopStatus.Invoke(new Action<string>(UpdateLoopStatusUI), statusText);
                return;
            }

            // UI线程直接更新
            labelLoopStatus.Text = statusText;
        }

        /// <summary>
        /// 异步停止识别10秒（避免阻塞定时器线程）
        /// </summary>
        private async Task StopRecognitionFor60sAsync()
        {
            _isStopped = true;
            _recognitionTimer.Stop();
            _stopTimer.Start();
            _hasFirstTwoSensors = false;

            // 核心修改：等待时间从60秒（60000ms）改为10秒（10000ms）
            await Task.Delay(10000);
            Console.WriteLine("10秒停止期结束，准备恢复扫描"); // 日志改10秒
        }

        /// <summary>
        /// 重置识别状态（统一方法，避免状态混乱）
        /// 优化：重置识别状态（同步重置单传感器等待计数）
        /// 优化：重置识别状态（同步重置首次识别标记，避免残留）
        /// </summary>
        private void ResetRecognitionState()
        {
            lock (this) // 线程安全锁
            {
                _currentSensors.Clear();
                _lastConfirmedSensors.Clear();
                _hasFirstTwoSensors = false; // 关键：重置首次识别标记
                _recognitionCount = 0;
                _singleSensorWaitCount = 0;
                UpdateSensorUIControls(new List<string>()); // 清空UI控件
                UpdateLoopStatusUI("识别状态已重置，继续扫描...");
                Console.WriteLine("识别状态已重置：清空所有历史记录和标记");
            }
        }



        // 以下为各步骤的具体实现（复用原逻辑，增加状态判断）
        private async Task<bool> TryOpenSerial()
        {
            buttonOpenSerial.PerformClick();
            await Task.Delay(1000); // 等待串口操作完成
            return serialDevice >= 0; // 原逻辑：serialDevice>=0表示串口打开成功
        }
        
        private async Task<bool> TryConfigReader()
        {
            buttonConfigReader.PerformClick();
            await Task.Delay(1000);
            // 实际需替换为硬件配置成功的判断（如：ReaderSDK.GetConfigStatus() == ConfigStatus.Success）
            return true; // 原逻辑假设配置成功，需根据真实API调整
        }
        
        private async Task<bool> TryReadConfig()
        {
            buttonReadConfiguration.PerformClick();
            await Task.Delay(1000);
            // 实际需替换为读取配置成功的判断（如：textBox15693DirInf.Text.Contains("配置读取成功")）
            return true; // 原逻辑假设读取成功，需根据真实反馈调整
        }
        
        private async Task<bool> TryExecTagOperation()
        {
            button15693DirExec.PerformClick();
            await Task.Delay(2000);
            // 判断标签操作成功：文本框含"操作标签"且标签数量>0
            return textBox15693DirInf.Text.Contains("操作标签:") && opTagUidNum > 0;
        }
       
        /// <summary>
        /// 检查阅读器硬件响应（示例：需根据实际硬件API调整）
        /// </summary>
        private bool CheckReaderResponse()
        {
            // 模拟硬件测试：发送一个无参数的状态查询命令
            // 实际场景需替换为硬件SDK的测试方法，如：return ReaderSDK.CheckStatus() == Status.Ok;
            bool isResponseOk = true; // 假设硬件响应正常（实际需对接真实API）
            if (!isResponseOk)
            {
                return false;
            }
            Console.WriteLine("阅读器硬件响应正常");
            return true;
        }

        /// <summary>
        /// 检查阅读器硬件响应（示例：需根据实际硬件API调整）
        /// </summary>
        private bool CheckReaderResponse_01()
        {
            // 模拟硬件测试：发送一个无参数的状态查询命令
            // 实际场景需替换为硬件SDK的测试方法，如：return ReaderSDK.CheckStatus() == Status.Ok;
            bool isResponseOk = true; // 假设硬件响应正常（实际需对接真实API）
            if (!isResponseOk)
            {
                return false;
            }
            Console.WriteLine("阅读器硬件响应正常");
            return true;
        }


        /// <summary>
        /// 重写 Dispose 方法确保非托管资源被释放：
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // 释放托管资源（组件、任务、事件等）
                components?.Dispose();
                _cts?.Dispose(); // 释放取消源
                _backgroundTask = null; // 移除任务引用
            }
            // 释放非托管资源（如操作系统句柄）
            ReleaseUnmanagedResources();
            base.Dispose(disposing);
        }

        /// <summary>
        /// 示例：启动后台线程（模拟实际业务中的异步操作）
        /// </summary>
        private void StartBackgroundTask()
        {
            _backgroundTask = Task.Run(async () =>
            {
                try
                {
                    while (!_cts.Token.IsCancellationRequested)
                    {
                        // 模拟耗时操作（如数据采集、定时刷新）
                        await Task.Delay(1000, _cts.Token);
                        // 注意：若需更新UI，需通过Invoke（但关闭时已取消，此处仅示例）
                    }
                }
                catch (OperationCanceledException)
                {
                    // 任务被取消时正常退出
                }
            }, _cts.Token);
        }

        /// <summary>
        /// 释放非托管资源（根据实际业务补充）
        /// </summary>
        /// <summary>
        /// 修复：补充串口关闭、DLL释放逻辑（核心！解决资源占用）
        /// </summary>
        private void ReleaseUnmanagedResources()
        {
            try
            {
                // 1. 优先关闭当前连接（根据_connectionType调用正确SDK接口，解决报错2）
                if (serialDevice > 0 && _currentConnType != ConnectionType.None)
                {
                    Console.WriteLine($"[资源释放] 正在关闭{_currentConnType}连接，serialDevice={serialDevice}");
                    int closeResult = -1; // 用int接收SDK返回值（SDK接口返回int）

                    // 根据当前连接类型调用真实关闭接口（从buttonOpenSerial_Click_Test提取的真实接口）
                    switch (_currentConnType)
                    {
                        case ConnectionType.SerialPort:
                            closeResult = hfReaderDll.hfReaderClosePort(serialDevice); // 串口关闭真实接口
                            break;
                        case ConnectionType.Usb:
                            // USB需关闭所有扫描到的设备（参考buttonOpenSerial_Click_Test逻辑）
                            closeResult = 0;
                            for (int i = 0; i < usbDevNum; i++)
                            {
                                int singleClose = hfReaderDll.hfReaderCloseUsb(usbHandleList[i]);
                                if (singleClose < 0) closeResult = singleClose; // 记录失败结果
                            }
                            break;
                        case ConnectionType.Tcp:
                            closeResult = hfReaderDll.hfReaderCloseSocket(serialDevice); // TCP关闭真实接口
                            break;
                    }

                    // 判断关闭结果（SDK返回int：非零=成功，零=失败）
                    if (closeResult >= 0)
                    {
                        Console.WriteLine($"[资源释放] {_currentConnType}连接关闭成功，返回值={closeResult}");
                        serialDevice = -1;
                        _currentConnType = ConnectionType.None;
                    }
                    else
                    {
                        Console.WriteLine($"[资源释放警告] {_currentConnType}连接关闭失败，返回值={closeResult}");
                    }
                }
                else
                {
                    Console.WriteLine($"[资源释放] 无有效连接可关闭（serialDevice={serialDevice}，连接类型={_currentConnType}）");
                }

                // 2. 释放HFREADER.dll（修正类型转换，解决报错3）
                if (hHFREADERDLLModule > 0)
                {
                    Console.WriteLine($"[资源释放] 正在释放HFREADER.dll，句柄={hHFREADERDLLModule}");
                    // 修正：FreeLibrary返回int，先接收再转bool
                    int dllFreeResult = hfReaderDll.FreeLibrary(hHFREADERDLLModule);
                    bool dllFreeSuccess = dllFreeResult != 0; // 非零=成功

                    if (dllFreeSuccess)
                    {
                        Console.WriteLine($"[资源释放] HFREADER.dll释放成功，返回值={dllFreeResult}");
                        hHFREADERDLLModule = 0;
                    }
                    else
                    {
                        Console.WriteLine($"[资源释放警告] HFREADER.dll释放失败，返回值={dllFreeResult}（可能被其他线程占用）");
                    }
                }

                // 3. 释放定时器等托管资源
                if (_recognitionTimer != null)
                {
                    _recognitionTimer.Stop();
                    _recognitionTimer.Dispose();
                    _recognitionTimer = null;
                }
                if (_stopTimer != null)
                {
                    _stopTimer.Stop();
                    _stopTimer.Dispose();
                    _stopTimer = null;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[资源释放异常] {ex.Message} | 堆栈：{ex.StackTrace}");
            }
        }


        /// <summary>
        /// 启动循环识别
        /// 优化：启动循环识别（移除错误的ID空值停止逻辑，确保持续扫描）
        /// 优化：启动循环（强制重置停止状态+日志）
        /// </summary>
        private async void StartLoop(ushort[] addrArray)
        {
            lock (this)
            {
                _isLooping = true;
                _isStopped = false; // 强制重置停止状态，避免启动时处于停止期
            }
            button15693DirExec.Text = "停止循环";
            UpdateLoopStatusUI("循环扫描启动中...");
            Console.WriteLine($"[循环启动] 已设置_isLooping=true | _isStopped=false | 间隔：{_loopInterval}ms");

            // 持续循环，仅在停止或暂停期退出
            while (_isLooping && !_isStopped)
            {
                ExecuteSingleRecognition(addrArray);
                await Task.Delay(_loopInterval);
            }

            // 循环退出时更新状态
            if (!_isStopped)
            {
                StopLoop();
                Console.WriteLine($"[循环退出] 手动停止循环，已调用StopLoop()");
            }
            else
            {
                Console.WriteLine($"[循环退出] 进入停止期，暂停循环");
            }
        }

        /// <summary>
        /// 停止循环识别
        /// </summary>
        private void StopLoop()
        {
            _isLooping = false;
            button15693DirExec.Text = "开始循环识别"; // 恢复按钮文本
            labelLoopStatus.Text = "已停止";
            this.button15693DirExec.Enabled = true;
        }

        /// <summary>
        /// 单次识别操作（提取原有核心逻辑）
        /// <summary>
        /// 单次识别核心方法（重新扫描会调用此方法）
        /// 修复：强化DataUpdated事件状态判断+数据有效性校验，确保推送不丢失
        /// </summary>
        private void ExecuteSingleRecognition(ushort[] addrArray)
        {
            try
            {
                this.button15693DirExec.Enabled = false; // 防止重复点击

                // 仅处理"直接操作标签"命令（根据原业务逻辑，数据推送在此分支）
                if (this.comboBox15693DirCmdSel.SelectedIndex == 0)
                {
                    #region 直接操作标签（核心数据获取与推送分支）
                    string sInfo = "";       // 硬件返回的原始数据（含传感器ID）
                    string sResult = "";     // 操作结果文本（如耗时、标签数量）
                    Byte[] blockAddr = new Byte[8]; // 数据块地址（硬件要求参数）
                    long delay = 0;          // 操作耗时（毫秒）

                    // 模式0：读取标签UID（最常用的重新扫描模式）
                    if (this.comboBox15693DirMode.SelectedIndex == 0)
                    {
                        this.textBox15693DirInf.Clear(); // 清空历史结果文本框
                        opTagUidNum = 0;                 // 重置标签数量计数器

                        // 1. 调用硬件SDK获取原始数据（核心：从阅读器读取传感器信息）
                        sInfo = DirReadTagUid(addrArray, ref opTagUid, ref opTagUidNum, ref delay);
                        // 2. 拼接操作结果文本（用于UI显示）
                        sResult = $"操作标签:{opTagUidNum}枚， 耗时:{delay}ms\r\n";

                        // 3. 保存原始数据到临时变量（供后续解析和推送）
                        _tempSensor1 = sInfo;
                        // 4. 解析传感器ID（格式化数据，不影响推送，但确保数据可读性）
                        ParseSensorData(_tempSensor1);

                        // 【核心修复1：DataUpdated事件状态判断+日志】
                        if (DataUpdated != null) // 判断事件是否有订阅者（避免空引用）
                        {
                            if (!string.IsNullOrWhiteSpace(_tempSensor1)) // 确保推送数据非空
                            {
                                // 打印订阅者数量+推送数据（便于排查：是否有外部订阅、数据是否有效）
                                int subscriberCount = DataUpdated.GetInvocationList().Length;
                                Console.WriteLine($"[数据推送-模式0] DataUpdated订阅者数量：{subscriberCount}，推送数据：{_tempSensor1}");
                                DataUpdated.Invoke(_tempSensor1); // 触发事件，推送数据到外部（如Form1）
                            }
                            else
                            {
                                Console.WriteLine($"[数据推送-警告] 模式0：_tempSensor1为空（硬件未返回数据，未推送）");
                            }
                        }
                        else
                        {
                            // 关键日志：提示外部未订阅事件（常见问题点）
                            Console.WriteLine($"[数据推送-失败] 模式0：DataUpdated无订阅者（请在Form1重新打开时订阅事件）");
                        }

                        // 5. 更新UI文本框（显示操作结果+原始数据）
                        this.textBox15693DirInf.Text = sResult + _tempSensor1;
                    }
                    // 模式1：读取标签UID+指定数据块（按需使用的扫描模式）
                    else if (this.comboBox15693DirMode.SelectedIndex == 1)
                    {
                        // （复用模式0的逻辑，仅SDK调用不同，核心推送代码一致）
                        Byte blockNum = 0;
                        Byte[] addr = new Byte[1];
                        string[] addrList = textBox15693DirBlkAddr.Text.Split('-');

                        // 解析数据块地址（硬件要求：最多8个地址）
                        for (int i = 0; i < 8 && i < addrList.Length; i++)
                        {
                            if (GetHexInput(addrList[i], addr, 1) <= 0) goto ERR; // 地址格式错误，跳转到错误处理
                            blockAddr[blockNum++] = addr[0];
                        }
                        if (blockNum == 0) { MessageBox.Show("请输入数据块地址"); goto ERR; }
                        if (blockNum > 8) { MessageBox.Show("最多只能操作8个数据块"); goto ERR; }

                        this.textBox15693DirInf.Clear();
                        opTagUidNum = 0;
                        // 调用SDK获取数据（读取UID+指定数据块）
                        sInfo = DirReadTagUidAndBlock(addrArray, blockAddr, blockNum, ref opTagUidNum, ref delay);
                        sResult = $"操作标签:{opTagUidNum}枚， 耗时:{delay}ms\r\n";

                        _tempSensor1 = sInfo;
                        ParseSensorData(_tempSensor1);

                        // 【核心修复2：模式1的数据推送（与模式0逻辑一致）】
                        if (DataUpdated != null)
                        {
                            if (!string.IsNullOrWhiteSpace(_tempSensor1))
                            {
                                Console.WriteLine($"[数据推送-模式1] 推送数据：{_tempSensor1}");
                                DataUpdated.Invoke(_tempSensor1);
                            }
                            else
                            {
                                Console.WriteLine($"[数据推送-警告] 模式1：_tempSensor1为空");
                            }
                        }
                        else
                        {
                            Console.WriteLine($"[数据推送-失败] 模式1：DataUpdated无订阅者");
                        }

                        this.textBox15693DirInf.Text = sResult + _tempSensor1;
                    }
                    // 模式2：写入标签数据块（较少用于重新扫描，保留推送逻辑）
                    else if (this.comboBox15693DirMode.SelectedIndex == 2)
                    {
                        // （逻辑与模式1类似，核心推送代码一致，避免冗余未完全展示）
                        Byte blockNum = 0;
                        Byte[] addr = new Byte[1];
                        string[] addrList = textBox15693DirBlkAddr.Text.Split('-');
                        // ...（省略地址解析和SDK调用逻辑）

                        sInfo = DirWriteBlock(addrArray, opTagUid, opTagUidNum, blockAddr, blockNum, ref delay);
                        sResult = $"操作标签:{opTagUidNum}枚， 耗时:{delay}ms\r\n";
                        _tempSensor1 = sInfo;
                        ParseSensorData(_tempSensor1);

                        // 【核心修复3：模式2的数据推送】
                        if (DataUpdated != null)
                        {
                            if (!string.IsNullOrWhiteSpace(_tempSensor1))
                            {
                                Console.WriteLine($"[数据推送-模式2] 推送数据：{_tempSensor1}");
                                DataUpdated.Invoke(_tempSensor1);
                            }
                            else
                            {
                                Console.WriteLine($"[数据推送-警告] 模式2：_tempSensor1为空");
                            }
                        }
                        else
                        {
                            Console.WriteLine($"[数据推送-失败] 模式2：DataUpdated无订阅者");
                        }

                        this.textBox15693DirInf.Text = sResult + _tempSensor1;
                    }
                    #endregion
                }

                ERR: // 标签操作异常时的统一出口
                this.button15693DirExec.Enabled = true; // 恢复按钮可用状态
            }
            catch (Exception ex)
            {
                // 捕获识别异常，提示用户并打印日志（避免程序崩溃，便于排查）
                MessageBox.Show($"识别出错：{ex.Message}");
                Console.WriteLine($"[单次识别-异常] {ex.Message}，DataUpdated未推送数据");
            }
            finally
            {
                // 无论成功/失败，均恢复按钮状态（防止按钮卡死）
                this.button15693DirExec.Enabled = true;
            }
        }

        /// <summary>
        /// 停止识别10秒（核心功能：暂停扫描、启动倒计时、重置关键状态）
        /// 触发场景：双传感器两次识别结果一致时调用
        /// 新增：线程安全锁、清空历史传感器集合，确保状态稳定
        /// 优化：10秒暂停逻辑（强制状态修改+定时器控制+异常兜底）
        /// </summary>
        private void StopRecognitionFor60s()
        {
            try
            {
                lock (this)
                {
                    // 1. 强制标记为“停止期”（阻止扫描）
                    _isStopped = true;
                    Console.WriteLine($"[暂停逻辑] 已设置_isStopped=true（停止期开始）");
                    Console.WriteLine($"[暂停逻辑] 进入10秒停止期：标记_isStopped=true"); // 文本改10秒
                    // 2. 强制停止扫描定时器（即使已停止，再次调用避免遗漏）
                    if (_recognitionTimer != null)
                    {
                        if (_recognitionTimer.Enabled)
                        {
                            _recognitionTimer.Stop();
                            Console.WriteLine($"[暂停逻辑] 已停止扫描定时器（_recognitionTimer）");
                        }
                        else
                        {
                            Console.WriteLine($"[暂停逻辑] 扫描定时器已停止（无需重复操作）");
                        }
                    }
                    else
                    {
                        throw new Exception("扫描定时器（_recognitionTimer）未初始化！");
                    }

                    // 3. 强制启动停止定时器（10秒后恢复）
                    if (_stopTimer != null)
                    {
                        _stopTimer.Stop(); // 先停止，避免重复触发
                        //_stopTimer.Interval = 60000; // 强制60秒，防止配置错误
                        _stopTimer.Interval = 10000; // 强制10秒，防止配置错误
                        _stopTimer.Start();
                        Console.WriteLine($"[暂停逻辑] 已启动停止定时器（_stopTimer），10秒后恢复");
                    }
                    else
                    {
                        throw new Exception("停止定时器（_stopTimer）未初始化！");
                    }

                    // 4. 强制重置双传感器状态（避免残留影响）
                    _hasFirstTwoSensors = false;
                    _lastConfirmedSensors.Clear();
                    _singleSensorWaitCount = 0;
                    _recognitionCount = 0;
                    Console.WriteLine($"[暂停逻辑] 已重置状态：_hasFirstTwoSensors=false | 历史ID清空 | 超时计数重置");

                    // 5. 强制更新UI（确保用户可见）
                    UpdateLoopStatusUI("识别已暂停，10秒后自动恢复...");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[暂停逻辑异常] {ex.Message} | 堆栈：{ex.StackTrace}");
                // 异常兜底：强制恢复基础状态，避免程序卡死
                _isStopped = false;
                if (_recognitionTimer != null && !_recognitionTimer.Enabled)
                {
                    _recognitionTimer.Start();
                    Console.WriteLine($"[异常兜底] 强制重启扫描定时器，避免卡死");
                }
                UpdateLoopStatusUI("暂停逻辑出错，已强制恢复扫描...");
            }
        }

        /// <summary>
        /// 停止定时器触发事件（10秒后执行：恢复扫描、重置停止状态）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StopTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                // 1. 停止倒计时定时器（避免重复触发）
                _stopTimer.Stop();
                Console.WriteLine("10秒停止期结束：停止倒计时定时器（_stopTimer）");

                // 2. 解除“停止期”标记
                _isStopped = false;
                Console.WriteLine("已解除停止标记（_isStopped=false）");

                // 3. 重启循环识别定时器（恢复1秒/次的扫描）
                if (_recognitionTimer != null && !_recognitionTimer.Enabled)
                {
                    _recognitionTimer.Start();
                    Console.WriteLine("已重启循环识别定时器（_recognitionTimer），恢复扫描");
                }

                // 4. UI状态更新（告知用户恢复扫描）
                if (labelLoopStatus != null && !labelLoopStatus.InvokeRequired)
                {
                    labelLoopStatus.Text = "10秒停止期结束，恢复循环扫描...";
                }
                else if (labelLoopStatus != null)
                {
                    labelLoopStatus.Invoke(new Action(() =>
                    {
                        labelLoopStatus.Text = "10秒停止期结束，恢复循环扫描...";
                    }));
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"StopTimer_Tick()恢复扫描出错：{ex.Message}");
                // 异常时强制重启扫描，减少程序卡死风险
                _isStopped = false;
                if (_recognitionTimer != null && !_recognitionTimer.Enabled)
                {
                    _recognitionTimer.Start();
                }
            }
        }




        #endregion 感应器

        private void buttonClearInfo_Click(object sender, EventArgs e)
        {

        }
    }
}
